This post discusses developing Windows programs using Microsoft’s Visual Studio with XAML (pronounced zammel).
The user interface of a Windows program using WPF is a tree of class objects. That tree has a single node at the top, and each node in the tree can have zero or more child nodes. The tree structure is exactly the type of structure produced by an XML document. The WPF designers used that fact to create a variant of XML, called XAML, for creating trees of WPF objects. XAML stands for eXtensible Application Markup Language and is pronounced zammel. The XAML parser interprets the XAML document and produces the tree of WPF objects, which constitutes the user interface.
Here are a few points from the book Illustrated WPF written by Daniel M. Solis.
• XAML is case sensitive, and follows most of the other XML syntax rules also.
• In a WPF program, although XAML is mostly used to specify the user interface, it can also be used to specify other .NET objects such as the Application object.
• WPF programs don’t need to use XAML at all. You can write WPF programs completely in C#, or other .NET languages.
• XAML isn’t limited to WPF.
− Windows Workflow Foundation (WF) also uses XAML, but uses it to specify the structure of workflows, rather than to produce UIs.
− Silverlight uses a subset of WPF XAML to build user interfaces for web applications.
• XAML source is called either markup or XAML code.
Although you can create a user interface without using XAML (in C# directly) using XAML is simpler. Also you can separate the UI design from the behaviour. This allows you to use two people to develop instead of one.
Every XAML file contains a XAML document, which specifies the UI’s logical tree. A XAML tree is made up of elements. Elements must be properly nested. The top or outer element is the root element and contains all the other elements.
Object Element Syntax
Objects in the user interface are represented by elements. An example of an object is a button or a window. We use XAML elements to represent WPF class objects. Each XAML element represents a WPF object.
The default syntax for an element comprises three parts—the start tag, the content section, and the end tag.
Click Me is the content, which is between the start tag and the end tag. Whatever is in the content section of the element is assigned to the default content property of the class.
If you want to set properties of the object, you can do that by assigning to XAML attributes, using a form called attribute syntax.
<Button Width="100" Height="50"> Click Me </Button>
The Width and Height are attributes of Button. Attributes must be placed inside the start tag, following the element name. An element can have any number of attributes, which must be separated by white space — not commas.
Sometimes you don’t need any content for an object. In the above code example you just remove Click Me. Alternatively you can use empty element syntax as shown below.
<Button Width="100" Height="50"/>
Object elements are elements the produce .NET objects. These object elements are the foundation of a XAML document. The element name can be either a .NET class or a .NET struct. The element name must exactly match the name of the corresponding .NET class. Remember that XAML is case sensitive. When creating an object from the XAML element, the XAML parser always uses the class’s parameterless constructor. You cannot specify a different constructor.
The element is translated into a class object in the following steps:
- Create the object, using the parameterless constructor.
- Set the default content property of the class object with the content part of the XAML element.
- Set the other class object properties to the values assigned to in XAML attributes.
Default Content Property
Every WPF class that can have content has a property that is specified as its default content holder.
This default content property is specified using the ContentPropertyAttribute attribute in the class declaration. (This is a .NET attribute, not a XAML attribute.)
The declaration of the default content holder might not be on the class itself, however. You might have to burrow down the inheritance tree a bit to find it. For example, if you go to the documentation for the WPF Button class, you won’t find mention of this attribute. But if you go down past the ButtonBase class to the ContentControl class and look at the C# section, you’ll find the following declaration. The parameter of the attribute contains the string “Content”, which specifies that for all classes derived from this one, it is the Content property that is the default content holder.
Different classes have different default content holder properties. For example, if you were to drill down from the ListBox control to its base class ItemsControl, you’d find that the ContentProperty in this case is the Items property.
Type Converters for Attributes
The Background property of a Button must be set with an object derived from the Brush class, but the attribute sets it with the simple string “Blue”. This post discusses the Brush class being used to set the background colour of the window.. With XAML, all you need to do is use the following code.
<Button Background="LightBlue" />
So, how can you assign a string to a property that requires some other type? The short answer is that the XAML parser converts it for you. The parser uses the class and property name to check the type of the property, and uses a TypeConverter for that type to convert the string to an object of the type required by the property. It converts it to SolidColorBrushes.LightBlue.
Property Element Syntax
XAML also provides another syntax for setting the values of more complex properties. The property is listed, not as an attribute inside the start tag, but using element syntax nested in the content part of the object element. The element name uses a two-part name in dot-syntax notation. The name consists of the class name and the property name, separated by a period (dot).
<Button Width="100" Height="50"> <Button.Background>LightBlue</Button.Background> </Button>
The attibute version (Background=”LightBlue”) is much simpler to read and you should use it when possible, however if you need to paint a button or another control with a linear gradient brush, for example, you will need to use code like the following.
<Button Width="100" Height="50"> <Button.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="LightBlue" Offset="0.0" /> <GradientStop Color="Blue" Offset="1.0" /> </LinearGradientBrush> </Button.Background> </Button>
This code will give you the following look to your button.
Attached Property Syntax
Attached properties are a special type of property that is defined in one class but used in another. It looks similar to the property element syntax. The following markup shows an example of using an attached property. If you look at the Button declaration, you’ll see an attribute assignment to a property called Grid.Row. Notice that the class name is Grid—not Button. That’s because the Row property is not declared in the Button class but in the Grid class. This is an attached property. An attached property is a property that is made available to each child object of an instance of the class that defines the property. The Grid.Row property is made available to the child Button control.
<Grid Margin="0,0,0,0"> <Grid.RowDefinitions> <RowDefinition Height="20" /> <!-- Grid.Row="0" --> <RowDefinition> </RowDefinition> </Grid.RowDefinitions> <Button Grid.Row="1" Background="LightBlue" Margin="62,22,140,79"> Click Me </Button> </Grid>
You use attached properties a lot when you are working with container controls. These assist with layout. There is the Canvas, DockPanel, Grid, StackPanel and WrapPanel. All of these derive from Panel.
When a container control contains multiple child controls, they are drawn in a specific stack order. If a control is higher up the stack, then it will be the control that you see in the overlap area. Controls lower down may be partially or completely hidden by controls above them. The stack order of controls is determined by the order in which they appear in the list of children for a container. The fi rst child in a container is placed on the lowest layer in the stack, and the last child on the topmost layer.