Did You Know… How to create XAML objects in Javascript?

I have had a very strong positive reaction to focusing on the Javascript in code behind for Silverlight 1.0, and so will devote not only today's Tip of the Day to a bit more on the topic, but will make sure that I do so on a frequent basis for a while.

Before I start: a small house keeping measure: the convention of starting every Tip of the Day with "Did You Know" is getting old. Thus, starting with the very next one it will be replaced with Tip Of The Day:

A reader (let's call this one Joe) writes,

What I've had trouble understanding is a small bit of code….

 Now, I have to say that the best way to get this kind of question answered is to post it to our forums; that way a lot more people see it a lot more quickly; but since you did write to me, I'll feel free to use it as grist for the Tip of the Day mill…

sender.fill = createLinearGradientBrush(sender.getHost(), sender);

function createLinearGradientBrush(plugin)
{
    var xamlFragment = '<RadialGradientBrush>';
    xamlFragment += '<GradientStop Color="LimeGreen" Offset="0.0" />';
    xamlFragment += '<GradientStop Color="Green" Offset="1.0" />';
    xamlFragment += '</RadialGradientBrush>';

    return plugin.content.createFromXaml(xamlFragment, false);
}

I understand 'what' it is doing and i understand 'why' it is doing it, but I don't know 'how'… I found the code to do it on a forum return plugin.content.createFromXaml(xamlFragment, false)

It isn't surprising you're baffled by this code as it is pretty advanced and it starts in the middle.

sender.fill = createLinearGradientBrush(sender.getHost(), sender);

What can we see or guess?

1. the purpose of this line is to fill sender with a LinearGradientBrush.

2.  the LinearGradientBrush will be created by the function createLinearGradientBrush.

3. The function createLinearGradientBrush takes two parameters: the getHost() method of the sender and the sender itself

4. The function crateLinearGradientBrush returns a Brush (and it better be a LinearGradientBrush or someone should be hurt) that be assigned to the sender's fill property.

What is sender?  It's not a big leap to assume sender is a shape.

How did we get here? We assume "here" is the middle of some function, and sender was a parameter to that function.

To do this right, I think we want to create a simple application that might get us to just this point.  So I'll fire up Visual Studio, strip out the starter application and put the following into Scene.xaml:

image

This creates two shapes, both of which respond to the MouseLeftButtonUp by calling an event handler method named onMouseUp, which we will expect to find in the code-behind file.

Note that you must provide a fill or if you click inside the shapes the event handlers will not fire! If you want the boxes to appear unfilled, you can use Fill="Transparent" as I've done here, but if you leave the fill out, it will default to null and clicking inside the shape will have no effect.

Here's the event handler:

image

  Presumably the event handler has work to do or there is more than one event handler. In any case, the programmer has decided to factor out the work of dynamically creating the Linear Gradient Brush. We now know what sender is; it is whatever shape we clicked on (in this case) but of course you can imagine other programs in which sender will be a shape retrieved by other means (picked from a menu in a drawing program?)

We saw CreateLinearGradientBrush in the original code above, but it is needlessly complex and we can simplify both the call to it and its own logic. Let's send just the sender, and encapsulate within createLinearGradientBrush the work of getting the SilverligthHost. First, we change the call,

image

Notice that we no longer ask the calling method to know that we need to retrieve the Silverlight control by calling GetHost; we just pass along the sender (the shape). Next, we create the brush by creating the XAML as a string and then asking the Silverlight control to create the brush we need from that string,

image

The top half of the method creates a string that replicates exactly how you would create the brush in XAML. To make it clear, I've put in the spacing I'd use in a XMAL file. Though this is not required, I believe it is good coding practice and far easier to maintain.

The bottom three lines (above the comment) act as follows;

var SilverligthHost = sender.GetHost()

GetHost() can be called by any Silverlight object as explained in this article and in the Silverlight 1.0 Help Files (an often overlooked and quite useful resource

image

Now, I admit it takes a while to translate some of that back into English, but what it tells you is that you can call GetHost on any Silverlight object (e.g., sender) and get back the plug-in (that is, the Silverlight control). Handy.

The second line is the key to this entire exercise

var brush = silverlightHost.content.createFromXAML(xamlFragment, false);

To understand this, you need to know that there is a method, createFromXAML that takes a string of XAML and returns a XAML object. That is explained in some detail in this video.

In addition it is helpful to know that the Silverlight control has sub-objects, one of which is named content, as explained in

this article.

You also want to know that createFromXAML takes two arguments, the second of which is used to create a unique namespace for the objects it creates, as explained both in the video and in the Silverlight documentation

image

I've commented out the line that is actually the way most programmers (or at least most of us who grew up in the C/Unix world where terseness is prized despite the fact that it makes for harder to maintain or understand code, and we should all be slapped silly)

return sender.GetHost().content.createFromXaml(xamlFragment, false);

I include it here not because I think it is the right way to do it, but because you'll see it and will want to know how to read it; the answer is "inside out" —

"Return from this method the result of calling GetHost on the sender object and then accessing the content sub-object on the returned Silverlight control so that you can call createFromXAML and pass in the text fragment that represents the object you are creating plus the boolean value false signifying that you do not want to protect namespaces." 

Easy.

So; when you bring up the application, the objects look like they are unfilled (their fill is transparent, but if you click on them, the event handler is called, which in turn calls createLinearGradientBrush passing in a reference to whichever object was clicked on. That object accesses the Silverlight control and asks it to instantiate a brush, which it uses to fill itself with color,

image

Hope that helps.

-j

image

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in z Silverlight Archives and tagged , . Bookmark the permalink.