Developing Silverlight 1.0 RIAs: XAML
(Read the intro here.)
First, XAML is an awkward language to work with. From a business perspective, this makes sense because Microsoft can push their Expression suite on developers and designers. But this is unacceptable for a client-side developer who wants to write markup by hand and is a Mac user.
XML is a terrible vehicle for describing anything more complicated than nested boxes. It is especially terrible with vectors. This is XAML generated by Blend to describe a tiny arrow pointing left:
-
<Path Width="5" Height="11.061" Fill="#FFFFFFFF" Stretch="Fill"
-
Data="M441.46101,604.74493 L445.48904,608.88653 441.52674,613.46898
-
442.43734,614.14997 446.91423,608.85206 442.3852,604.04503 z"
-
Opacity="1" x:Name="back_arrow" Canvas.Left="6" Canvas.Top="8"
-
RenderTransformOrigin="0.5,0.5">
-
<Path.RenderTransform>
-
<TransformGroup>
-
<RotateTransform Angle="-180"/>
-
</TransformGroup>
-
</Path.RenderTransform>
-
</Path>
Opening up 2000 line XAML files full of markup like this is headache inducing.
Second, XAML in SL 1.0 is the Anti-DRY language. It lacks concepts like cascading styles and class names, so if you want all your TextBlock elements to be red, you have to specify Foreground="#FFFF0000" for each one.
It gets worse for repeating elements programmatically. Say you have XAML for a button with a TextBlock label, and you want to create four of them to make a menu:
-
<Canvas Width="100" Height="20">
-
<Rectangle Fill="#FF000000" RadiusX="5" RadiusY="5"
-
Width="100" Height="20">
-
<TextBlock x:Name="buttonLabel" Canvas.Top="3"
-
Canvas.Left="5" Foreground="#FFFFFFFF">Label</TextBlock>
-
</Rectangle>
-
</Canvas>
Of course, you’ll want programmatic access to that TextBlock so that you can change the label text. But because there is only one namespace for x:Names (x:Name="buttonLabel" can only be used once), adding more than one to the XAML hierarchy will throw an exception. Also, there are no utilities like .getElementsByTagName. Solutions like button.children.getItem[0].children.getItem[0] are brittle and don’t scale.
There is a solution to this, but it was nearly impossible to find in the Silverlight 1.0 documentation. The createFromXaml method takes a second boolean argument that can create a new, separate namespace for x:Names. This allows you to create multiple XAML objects from the same source and add them to the XAML hierarchy without x:Name collisions.
A caveat to this technique is that findName won’t find elements created in a new namespace, so you have to save a representation of each new element in JavaScript.
My methodology for using XAML tries to tackle these two big challenges. It breaks down to these steps:
- Use images instead of XAML vectors when the file size overhead allows it.
- If Blend is used, only create small, isolated pieces of XAML so each is easier to digest and manipulate.
- Zip up every XAML file and download it all at the beginning. XAML files are usually light enough that it shouldn’t noticeably delay the start of your application.
- Create XAML elements dynamically from the files in the zip file. Use
createFromXaml(text, true)for repeated elements and always save a representation of the elements in JavaScript to manipulate later.
I built a number of utility functions to make this methodology very easy to use. Here is an example:
-
var ComplicatedXamlCreator;
-
new XamlDownloader('cmn/xaml/packaged/xaml.zip', {
-
onComplete : function(zip) {
-
ComplicatedXamlCreator = zip.save('complicatedXaml.xaml');
-
zip.destroy();
-
}
-
});
-
-
// later, create a xaml object and add it to the XAML hierarchy
-
var xaml = ComplicatedXamlCreator(true);
-
root.children.add(xaml);
-
-
// or create multiple xaml objects and manipulate independently
-
for (var i = 0; i < 10; i++) {
-
var xaml = ComplicatedXamlCreator(true);
-
-
// finds a different TextBlock element each iteration
-
var label = xaml.findName('label');
-
label.text = 'Button Label ' + i;
-
-
root.children.add(xaml);
-
}
My XamlDownloader utility is a simple wrapper for the Downloader class that passes back an instance of a ZipHandler class. The save method grabs a XAML file out of the zip file and returns a XAML creation function that can be run as many times as necessary.
Because the XamlDownloader utility creates a closure around a Downloader instance, you have to destroy that instance or you’ll create a massive memory leak. The WWE project would bring down a fresh instance of Firefox 2 in half an hour easily.
- Intro
- Part 1: Xaml
- Part 2: JavaScript Optimization
- Part 3: JavaScript Architecture
[...] VSM breaking the XAML - Silverlight 2 issue and workaround. Saved by laxkid275 on Thu 02-10-2008 Developing Silverlight 1.0 RIAs: XAML Saved by realcissy on Wed 01-10-2008 VB.NET XAML Classes and Namespaces Saved by cavemanlawyer15 [...]
Recent Links Tagged With "xaml" - JabberTags — October 3rd, 2008 at 4:19 am