devxlogo

Learn to Write XAML Applications Today with Xamlon

Learn to Write XAML Applications Today with Xamlon

AML is an XML-based markup language that describes UI content and behavior. The concept is similar to the combination of HTML and JavaScript used in Web applications today, but far more ambitious. “Avalon” is the codename for the runtime that interprets XAML documents and turns them into interactive applications. You can download a 30-day beta of Xamlon, although you’ll need to register to get a product key. Installing Xamlon via the MSI download is painless; you get the Xamlon engine, a suite of samples, a XAML viewer, and “XamlPad”, a standalone XAML editor of questionable utility other than its ability to import SVG files.

If you have Visual Studio 2003 installed, the install also registers a “Visual Designer” plug-in, providing Xamlon project templates and automatic “class behind” generation when you add a XAML file to your project (see Figure 1 and Figure 2). Unfortunately, the plug-in only works with Visual Studio 2003; I tested this on both Visual Studio 2002 and a recent Visual Studio 2005 beta without success. With that said, there’s more to Xamlon than its Visual Designer; so I’ll show you how to wire up XAML documents from scratch. Doing that provides a better understanding of exactly what the designer does (and doesn’t) do for you, and you’ll also find it easier to debug the code the designer produces if you do decide to use it. In addition, designing manually gives you a chance to see what XAML’s all about, even if you don’t have Visual Studio installed at all.

Author’s Note: Because this review is based on a beta release, the samples supplied with this article may not compile or run correctly with future versions. In addition, because the release against which they have been compiled is time-limited, you may need to download an evaluation copy of Xamlon to compile and/or run these samples.

?
Figure 1. Xamlon Project Templates in Visual Studio: The Xamlon installation adds new project types and templates to Visual Studio.
?
Figure 2. Xamlon Class-Behind Files: Similar to other project types, Xamlon’s Visual Studio add-in automatically generates “class-behind” files to handle event wiring, resource loading, and other functions.

XAML Document Structure
The code below shows a typical XAML document. Running it produces a display like Figure 3.

?
Figure 3. A Xaml document hosted by the Xaml viewer. The document doesn’t fill the view because it hasn’t specified window constraints.
                                                                                                                                                                                                        

The document declares a Canvas object with a specified width and height. The canvas is the drawing surface on which the runtime engine lays out the various graphics primitives. In this case, there’s only one primitive?a Rectangle object with a five step gradient fill, which I’ve largely adapted from one of the sample projects. You’ll also see various namespace declarations in the preceding code. The schema declaration isn’t strictly necessary, but will probably become so later when XAML parsers validate documents against formal XSD schemas.

For now, the “Definition” namespace is far more important (referred to here via the “def” prefix) because it plays the role of binding the declaration of a LinearGradientBrush to the Fill attribute of a Rectangle. XAML makes this possible through something variously referred to as either complex properties or composite properties. You can identify a complex property by its “X.Y” element declaration, meaning both that Y is used to alias an XML fragment declared in-place, and that Y is a property of X. In one sense, this is a practical workaround for the fact that XML node structures can’t be directly assigned to XML attributes; but at a conceptual level it’s also the realization of one of XAML’s fundamental design tenets?that the object model and markup mutually describe one another (a precept already followed successfully by other XML APIs such as MSBuild and ASP.NET). In this instance, Canvas.Resources and LinearGradientBrush.GradientStops are both examples of complex properties. When the Rectangle references {ShineGradient}, the runtime engine attempts to resolve the reference within the current scope. Because Rectangle’s parent is Canvas, it searches Canvas’s complex properties (Canvas.Resources) for an appropriate declaration. Having identified the LinearGradientBrush declared there, it then instantiates this brush and passes back a reference to it. You’ll come across many other complex properties as you work with XAML, and a detailed discussion of these is beyond the scope of this article. For now, it’s sufficient to recognize their format, X-dot-Y, and to understand that they underpin both XAML’s object representation and its object serialization philosophy.

Now look at Figure 3 again. The whitespace at the bottom right exists because the XAML document declares a Canvas object, but doesn’t specify a Window in which to host it, so the Xamlon engine creates a default window whose dimensions are constant?and those dimensions have nothing to do with the size of your Canvas. If you resize the window it clips the gradient fill naively because there’s no way to tell the renderer to do anything different. Let’s add some events to rectify this, and find out how “class behind” code really works in the process.

Working with “Class-behind” Code
Xamlon terminology often uses the expression “class-behind” to refer to the fact that XAML documents can interoperate with code written in managed languages (e.g. C# or VB.NET). Specifically, class-behind files can access the XAML document object model to add, remove, or otherwise manipulate the elements within it. More importantly, XAML documents require a class-behind if they are to respond to user or framework events (Load, Resize, Click, etc.).

?
Figure 4. XAML Event-mapping: You can map events between a XAML document and a “class-behind” file associated with it. This figure shows the message box that pops up when you click the form.

The following example modifies the existing XAML file and adds a Click event handler. Doing this requires a number of changes.

First you’ll need to create a C# class library project that exposes a standard Windows Forms OnClick handler with the usual signature.

   public void OnClick(object sender, EventArgs e)   {      MessageBox.Show("Hello", "Message");   }

Next, you must restructure the XAML document. Because the Canvas object can’t respond directly to events, the restructured version nests it within a Window object, wires the Click event to the name of the event handler, and adds a processing instruction to identify the namespace, class name, and physical location of the assembly containing the event handler. If you compile Example1, launch Example1.xaml, and then click on the window, you’ll see a MessageBox as in Figure 4.

Referencing XAML Documents at Runtime
Displaying static data is all very well, but given the graphic complexity exposed by the XAML API, you’re likely to want to change things at runtime, too. There’s actually more than one way to achieve this, but the most flexible strategy?and the one Xamlon’s Knowledge Base endorses?is to add a “class-behind” file that implements the System.Windows.Serialization.IPageConnector interface. IPageConnector contains a single Connect method:

      bool Connect(string id, object target)

The easiest way to understand what’s required is to walk through an example step by step. First, create a new “Class Library” project and add references to both System.Drawing and to Xamlon.dll (which installs to the c:Program FilesXamlonlib directory by default). Next, implement the IPageConnector interface as follows:

   public bool Connect(string id, object target)   {     switch (id)     {         case "Window1":            MessageBox.Show("Connecting Window1");            System.Windows.Window window = target as                System.Windows.Window;            window.Width = 300;            window.Height = 300;            window.AddText(               "Text added into Window title");            return false;            default:            return false;      }   }

Finally, you need to tell your XAML document to use the interface you have supplied. The XAML runtime will look at any “Mapping” processing instructions you’ve included in your XAML document to determine which assemblies it should investigate. It will then attempt to query each of those assemblies for an implementation of IPageConnector, using the “Namespace.Class” identifier you may (or may not) have cited in your document with a def:Class attribute. Assuming it locates a suitable class, it will call that class’s Connect() method, passing in the ID of the object in question, as well as the object itself. In this case, all I’ve had to do to get the XAML runtime to call my IPageConnector implementation is to update Example1.xaml so that its def:Class refers to Example2.Example2, and explicitly add an ID attribute to my Window element, because Connect() uses that ID to identify which element is getting connected:

      

Usually, you’d take the opportunity to cache any objects passed into Connect() so that you can explicitly manipulate them later. For demonstration purposes, though, the sample code just resizes the window and changes its title. You’ll find the complete project in the Example2 folder in the downloadable sample source.

The TransformDecorator Object
Earlier I pointed out that without special “class behind” code XAML documents don’t rescale themselves as they are resized. There’s an easy solution, though. Just wrap your Canvas object in a TransformDecorator element, which has a property called Transform. Many of the samples draw on common class-behind code in the assembly zoom.dll for just this purpose. You’ll find the source code for zoom.cs in your c:Program FilesXamlonSamplesVector directory. Having hooked the Window’s Load and Resize events using the IPageConnector interface, the class caches the original Window dimensions in its OnLoad handler and recalculates scaling factors in its OnResize handler as follows:

   public void Load(object sender, EventArgs e)   {      System.Drawing.Size size = this._root.ClientSize;      this._originalWidth = size.Width;      this._originalHeight = size.Height;   }              public void Resize(object sender, EventArgs e)   {      System.Drawing.Size size = this._root.ClientSize;      double width = size.Width;      double height = size.Height;         double factorX = (width  != 0.0) ? width  /          this._originalWidth : 1.0;      double factorY = (height != 0.0) ? height /          this._originalHeight : 1.0;      double factor = Math.Min(factorX, factorY);         this._zoom.Transform = new ScaleTransform(         factor, factor);   }   

Now open up one of the Vector samples, for example translateTransform.xaml (in the Vector/Transforms subdirectory). The relevant wiring looks like this:

                                ... XAML primitives ...                  

Note, of course, that you’ll want to specify initial dimensions for the Window node so that the TransformDecorator starts with appropriate scaling factors.

Using the Visual Designer

?
Figure 5. Xamlon Visual Designer: The Visual Designer makes it possible to visualize XAML documents within Visual Studio itself. You can switch between “Design” (code) and “Xaml” (visualization) mode.

Wiring events is much easier inside the Visual Designer. In fact all you have to do to map most common events is to select the event from the “Properties” window while visualizing a XAML document with the focus set to the control whose events you are interested in. The Designer will stub out the method for you, just like a Windows Forms application. However, having hand-wired the events already, you now have some insight into how the Designer works. For example, if you take the original XAML file shown in this article, and drag-and-drop it into Visual Studio, you’ll see something very different. Figure 5 shows how the file appears graphically, and Listing 1 shows the changes the Visual Designer has made to it.

In Listing 1, the Visual Designer has mapped two namespaces, “wf” and “wfi” (for Windows.Forms and Windows.Forms.Integration respectively). It has also wrapped the Canvas node within an ElementHost node, wrapped this in turn within a Form.Controls node, and finally, added a Form wrapper around the whole thing. One effect of these changes is that they let the Visual Designer differentiate between “standard” Windows Forms UI elements and XAML-specific UI elements by mapping them to different namespaces. The Visual Designer also wraps XAML content within an ElementHost, which means you can embed XAML in a standard Windows Form, much like a Panel object. So if you think XAML’s Button object looks remarkably similar to the existing Windows Forms Button, it’s because the two are in fact identical!

Through IPageConnector you gain the ability to manipulate existing XAML elements as they get instantiated. Sometimes, though, you’ll want to add data after your XAML window is up and running. Xamlon allows you to inject XAML data at runtime using the System.Windows.Seralization.Parser.LoadXml() method. You do still have to jump through a few hoops to get new XAML content integrated into a running WinForm though, so the sample Example 3 Project illustrates the techniques.

?
Figure 6. Coloring by Numbers: The Toucan Tester shows an example of dynamically altering the underlying XAML content and displaying the results.

First, the project hooks the Form’s Load() event to load the XAML document toucan.xaml using a TextReader (XAML documents are fully XML compliant) and then caches it in an XmlDocument. When you click the form, the project uses an XPath query to change all the Fill attributes within the document, which define the colors used for the various parts of the toucan. The code converts the altered document into a MemoryStream, loads this into Xamlon’s parser to create a FrameworkElement object, locates the ElementHost control currently hosting the toucan, and finally, calls AddChild() with this new FrameworkElement. Calling AddChild on an ElementHost actually replaces any existing content with the new content you supply (perhaps AddOrReplaceChild would be a more accurate signature). The result is that the toucan changes color randomly, every time you click the “Color Me” button (see Figure 6). It’s a stylized example, but it does show you how to combine XAML with XSLT or XPath, and how to get the runtime engine to display updates you make dynamically.

More often, though, you’ll want to skip the loading step and work directly with the XAML primitives. The principle is basically the same. Take a look at the Xamlon “Floating Circles” sample application (ApplicationsFloating_Circles) which does just this, dynamically adding all its elements to a blank canvas at runtime.

The Future of Xamlon
Xamlon’s founders haven’t chosen the easiest path. On one hand, Xamlon may find market share because it offers Avalon’s technology today, but will you want to use Xamlon when Avalon is finally released? A few months ago, many would have considered Xamlon because it offers back-level support for all the Windows variants that can run the .NET 1.1 runtime, but Microsoft recently pledged to implement WinFX?the technology that underpins Avalon?on both Windows XP and Windows Server 2003. That still doesn’t give Avalon quite as wide an O/S base as Xamlon?but does it make sense to target Windows 98 in 2005?

Despite Microsoft’s announcement, I feel that there is a niche and market for Xamlon among developers and architects who need to begin getting up to speed on Avalon now, gaining the experience to make strategic decisions that may not include Xamlon itself, but may well include Longhorn. Releasing public betas so that the developer community can get to grips with this new technology has done much to endear me to the Xamlon initiative. While Xamlon itself remains a bit ragged round the edges in some respects (I’m particularly thinking of its dearth of SDK documentation), it’s generally useable and stable enough that you can develop practical proof-of-concept applications with it out-of-the-box (for example, it comes with both a Calculator and an implementation of Solitaire as sample projects). This, taken together with Paul Colton’s pledge, as Xamlon’s founder, to “track Avalon” through XAML’s changing specification forces me to conclude that Xamlon completely justifies its $400.00 price, and gives forward-looking developers a definite advantage when the first formal Longhorn projects kick off.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist