One concept I had to get my brain wrapped around when learning WPF was the tight relationship XAML tags and .NET types had. I’ve done a lot of desktop development in the past (GDI/GDI32, User32, WinForms …), but I’ve done mostly ASP.NET development the past couple of years. They are very different frameworks in a lot of areas (statefull vs. stateless, procedural vs. declarative, etc.).
In WinForms, you could use the Visual Studio designer and drag-n-drop to create your UI. But behind the scenes it was just converted to C# (or VB.NET or [insert .NET language of choice here]) code that instantiated all the controls, set their properties, etc. XAML is completely declarative. The XAML you write is not converted to C# code that gets compiled with your app. It’s tokenized into BAML and embedded in your app as a resource that is loaded at runtime and parsed by the XAML parser.
One core concept with XAML is that its purpose is to declaratively instantiate and initialize .NET objects. Let me state that one more time, because it’s a very important concept. The purpose of XAML is to declaratively instantiate and initialize .NET objects. Every tag in XAML has a one-to-one correlation to a .NET type (or property on a type). This is fairly different from ASP.NET where the tags are fairly loosely tied to .NET types (a <div runat=”server” …> tag maps to a .NET type named HtmlGeneric, not to a .NET type named div).
Let’s look at a quick example of XAML:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="TestApp.ExampleWindow" Title="Example Window" Height="100" Width="200"> <Window.Background> <LinearGradientBrush> <LinearGradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="0.0" Color="Red" /> <GradientStop Offset="1.0" Color="Blue" /> </GradientStopCollection> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Window.Background> <Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Press Me" /> </Window>
This is equivalent to the following C# code (the xmlns, xmlns:x and x:Class attributes on the Window tag tell the XAML parser what namespaces to use [similar to “using …” statements in C#], and what .NET type is the “codebehind” for this XAML [similar to the codebehind concept in ASP.NET] ):
Window window = new Window(); window.Title = "Example Window"; window.Height = 100.0d; window.Width = 200.0d; LinearGradientBrush brush = new LinearGradientBrush(); brush.GradientStops = new GradientStopCollection(); brush.GradientStops.Add(new GradientStop(color: Colors.Red, offset: 0.0d)); brush.GradientStops.Add(new GradientStop(color: Colors.Blue, offset: 1.0d)); window.Background = brush; Button button = new Button(); button.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; button.VerticalAlignment = System.Windows.VerticalAlignment.Center; button.Content = "Press Me"; window.Content = button; window.Show();
Notice the direct correlation between the tag names in the XAML and the .NET types? Also note that how the XAML parser behaves with child elements differs based on whether there’s a dot in the child element’s tag name and the parent element’s type.
- The first child element of the <Window …> element is <Window.Background …>. The dot in the child element’s tag name tells the XAML parser that this is actually setting a property on the Window object.
- The second child element of the <Window …> element is <Button …>. There’s no dot in the child element’s tag name so it’s content. Window’s Content property (which is decorated with the [ContentProperty …] attribute to tell the XAML parser that’s where Window’s content goes) is of type Object, so the XAML parser knows to assign the Button object to the Window’s Content property.
- The <LinearGradientBrush> child element of <Window.Background> gets assigned to the Window’s Background property because Windows.Background is of type Brush and LinearGradientBrush inherits from Brush.
- The <GradientStop …> child elements of the <GradientStopCollection> element are handled a little differently. Since GradientStopCollection is an IList, the XAML parser knows to call GradientStopCollection’s .Add method to add the child elements.
Also of interest here are the .NET type converters that are being used. GradientStop’s Color property doesn’t take a string, it takes a Color object. But there’s a type converter in .NET that will convert a string to a Color object so the string “Red” is converted to a Color object before being assigned to the GradientStop’s Color property. If a type converter doesn’t exist, or the property is simply too complex to set with a string attribute, the syntax seen with the <Window.Background> tag can be used to set the property instead of attributes (Color=”Red”) directly in the element’s tag.
There’s a lot more of extreme interest going on here that I could discuss (such as the fact that the <GradientStopCollection> element could have been eliminated since the XAML parser knows that LinearGradientBrush.GradientStops property is of type IList), but this post is about the tight correlation between XAML tags and .NET types. So, I’ll save additional ramblings for future posts.