There’s no denying that Adobe has an advantage in the RIA space as the first to market with their Flash platform. But it’s also a weakness that Microsoft has taken full advantage of with their recently released Silverlight 1.0 platform.
For the most part, Flash is a black box of compiled code, and in the web 2.0 world is sort of a second class citizen. From the early days of the Internet, the world wide web was always about sharing and the openness of ideas and code. Most of the early surfers/developers learned by looking at other peoples code. “View Source” was one of the best way to teach yourself web development, and even to this day is a great way to learn by example. Because Flash is a binary black box, it’s very difficult to learn from others. Some may call this ‘job security’ but in the true spirit of the Internet it could easily be considered greed. This is exactly the Achilles heel that Silverlight is trying to exploit. Granted Microsoft does have their work cut out for them to catch up to Adobe but Silverlight is perfectly positioned to be treated as a first class citizen within the browser — a position Flash will have a hard time adjusting to. With Silverlight everything is one cohesive collection of markup and scripts all easily parsed and processed — it’s a true extension of web 1.0, 2.0, and beyond.
With a Silverlight application anyone can view your source and learn from your success (as well as your mistakes!). You can look at my application and borrow the XAML code for one of my buttons, change the color and size and create your own button variation. Someone else may then come along and borrow your JavaScript code for handling mouse-clicks to add their own custom functionality. Through this constant sharing and tweaking, the platform grows stronger and development best practices start to emerge.
Which brings me to the title of this post… The missing Silverlight function. Anyone that’s ever seen a line of JavaScript code before is familiar with the DOM method getElementById(). This function allows you to select any named HTML element in a web page to program against. Silverlight has an equivalent function for selecting named XAML elements: findName(). Another useful JavaScript function when working with HTML/DOM is getElementsByTagName(). This little guy will return a collection of HTML elements of a particular type, paragraph tags for example (all <p> tags) which you can then program against. Unfortunately Silverlight does not have an equivalent function to grab all elements of a particular type. You can however create your own! Below is a first pass at some code that does exactly that. It takes two parameters, the first is a reference to the parent Canvas that you want to explore, and the second is a string indicating the tag/Element you are looking for. What you get back is an array of XAML elements of that type.
function findByTagName(parentCanvas, tagName) { // _plugin is a reference to the Silverlight plugin. var parent = _plugin.content.findName(parentCanvas.Name); if (parent.toString() != "Canvas") { return null; } var childrenCount = parent.children.count; var objects = new Array(); for (var i = 0; i < childrenCount; i++) { var child = parent.children.getItem(i); if (child.toString() == tagName) { objects.push(child); } } return objects; }
This comes in real handy when you are working with a RIA where you have a lot of things that are being created dynamically on the fly (using createFromXaml()). For example you may know that your application is going to be creating multiple instances of a collection of UI Elements, and you don’t want to have to name everything and store references to their names. Instead you just know that you have a UI element that has X number of children of Y type of elements (e.g. I have a canvas that contains 2 images, a media element, and 4 rectangles and this collection of objects is repeated several times throughout the application). So instead of having to keep track of 8 elements times the number of instances, I can just keep track of the containing canvas. Pass a reference to the canvas, and the type of element I want to program against to the above function and it makes thing a whole lot easier to manage.
var myRectangles = findByTagName(myCanvas, "Rectangle"); for (var i = 0; i < myRectangles.length; i++) { //do something to each Rectangle within myCanvas }
Below is a pretty simple example of it in use (requires Silverlight 1.0 plugin). Clicking on each rectangle moves it’s parent Canvas so all rectangles move as one collection. I’m sure you can probably think of 1,000 more usable real world scenarios!
{ 3 comments… read them below or add one }
Hey great writeup …. BUT … this is only true for Javascript developers using Silverlight. For people using C# or any of the other .NET languages… the code is compiled into a dll just like Flash is compliled to swf.
This is awesome, thanks for sharing Jason.
Really useful.
I extended the function to recurse all canvas objects if the child itself was a canvas. This then truly behaves like getElementsByTagName).
I used the routine to fix up all the Image Source attributes to use relative paths.