Table of contents
- Part 1 (XAML): Learn about XAML and how it is used in WPF applications.
- Part 2 (Layout): Learn about layout panels and how they are used to construct user interfaces.
- Part 3 (Data binding): Learn how WPF data binding works and how it can be used.
- Part 4 (Data templates and triggers): Learn how data templates and triggers work and how they can be used.
- Part 5 (Styles): Learn about how UIs can be styled in WPF.
Introduction
This article is the first in a series which reviews some important features of Microsoft's Windows Presentation Foundation (WPF). The entire series barely scratches the surface of the immense WPF platform, and it does not dive too deeply into any particular topic. The purpose of this series is to familiarize the reader with the basic WPF programming model to the point where he/she is comfortable enough with WPF to fully understand the, rather silly, WPF Horse Race application (available for download via a link at the top of this page).
The subject matter is presented in the context of a completely impractical horse racing application, as seen in the screenshot above. The application was designed with the intention of being used as the focal point of this series. I tried to find the right balance between making the demo application simple enough to be understandable to a WPF newcomer, yet complicated enough to actually do something interesting (or at least mildly amusing).
Prerequisites
In order to run a WPF application you need the .NET Framework version 3.0, or greater. Windows Vista has the .NET Framework v3.0 installed by default, so you only need to install it if you have Windows XP SP2.
To develop WPF applications you should have Visual Studio 2005 with the "Orcas" extensions, or a later version of Visual Studio, and also the Windows SDK. Refer to the External Links section at the end of this article for links to relevant resources.
What is XAML?
XAML stands for eXtensible Application Markup Language. It is an all-purpose XML-based language used for declaring object graphs, which are instantiated at runtime. XAML is used by WPF developers to declare the layout of a user interface (UI), and the resources used in that UI.
It is not at all necessary to use XAML when programming in WPF. Anything that can be done in XAML can also be done in code. Using XAML makes many UI development scenarios much easier and faster, such as creating the layout of a UI and configuring styles, templates, and other WPF-specific entities discussed later in this series.
Performance impact
When you compile a WPF application in Visual Studio it will compile your XAML files into a compressed representation known as Binary Application Markup Language (BAML). The BAML is then saved as a resource in the resultant assembly. When that assembly is loaded and the resource is requested, the BAML is streamed out and very quickly turned into the object graph described by the original XAML.
This two-step process allows the XAML parsing to occur at compile time, thus mitigating the performance overhead of using a text-based object instantiation technology. With that said, it is possible to load XAML programmatically via the XamlReader.Load
method. Dynamically loading XAML can be useful in a variety of situations, such as when a volatile portion of your UI is periodically downloaded from a server via XML Web services.
Basic syntax
Since XAML is an XML-based language, it should be quite simple and straightforward for anyone with XML experience. There are two different uses for XML elements in XAML; elements that represent objects and elements that represent properties of objects. An XML attribute always represents a property or event of an object. That's it; it is that simple. There are a few other concepts built on top of those fundamentals, but XAML never becomes complicated.
For example:
<Button Content="Click Me" Click="OnButtonClick">
<Button.Background>
<LinearGradientBrush>
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Green" Offset="1" />
</LinearGradientBrush>
</Button.Background>
</Button>
That XAML results in a funky little button, which is rendered like this:
Let's dissect that XAML to see how it works. The <Button>
element declares that an instance of the Button
class will be created. That Button
object will have its Content
property set to the string "Click Me"
. The Button
's Click
event will be handled by a method called OnButtonClick
in the code-behind file (we'll get into code-behind files soon).
The next element is <Button.Background>
, which is said to use the "property element syntax". That XML element represents the Background
property of the Button
being configured. The child element of a property element is the value to which the property is set. In this case, the Background
property is set to a LinearGradientBrush
object.
That brush has two <GradientStop>
child elements, which might seem confusing at first. What are those GradientStop
objects doing there? What are they being assigned or added to? The answer lies in the fact that XAML has some "shortcuts" built in which allow you to specify a property on a class which is considered to be the "content property." You do not need to use the property element syntax to assign a value to the "content property" of a class. Since LinearGradientBrush
's content property is the GradientStops
property, the following XAML is equivalent to that seen above:
<Button Content="Click Me" Click="OnButtonClick">
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Green" Offset="1" />
<LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
</Button>
The C# version
In case you are curious about what that XAML would look like if it was written in C#, here's the translation:
Button b = new Button();
b.Content = "Click Me";
b.Click += this.OnButtonClick;
LinearGradientBrush lgb = new LinearGradientBrush();
lgb.GradientStops.Add( new GradientStop( Colors.Yellow, 0 ) );
lgb.GradientStops.Add( new GradientStop( Colors.Green, 1 ) );
b.Background = lgb;
Markup extensions
The XAML parser also knows how to work with a special construct known as the "markup extension." Markup extensions allow you to compactly configure objects and reference other objects defined elsewhere in the application. They are used when setting a property on an object, either via an XML attribute or the property element syntax. Markup extensions are used for things such as specifying a null
value, declaring an array, referencing an object held in a resource dictionary, binding one property to another, and much more.
The following XAML is roughly equivalent to the example shown previously (with a few minor changes):
<Grid>
<Grid.Resources>
<LinearGradientBrush x:Key="FunkyBrush">
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Green" Offset="1" />
</LinearGradientBrush>
</Grid.Resources>
<Button Background="{StaticResource FunkyBrush}">Click Me</Button>
</Grid>
Notice that the Button
's Background
property is set, via an XML attribute, to {StaticResource FunkyBrush}
. When an attribute is set to a value which begins with { and ends with }, then a markup extension is being used.
In this case the StaticResourceExtension
class is being used to reference a LinearGradientBrush
stored in the Grid
's resource dictionary. (Note: Grid
is a layout panel in WPF, not a tabular data presentation control like you might expect.)
Code-behind files
XAML is compiled down into a class. Unless you specify the class name it should use, the compiler will generate a class name for you. However, when you apply the x:Class
attribute to the root XML element in a XAML file, you can create a partial class in C# or VB.NET which will be merged with the XAML partial. This is how you can associate behavior with the layout and visuals declared in XAML.
For example, in the demonstration above we created a Button
in XAML and assigned an event handling method to its Click
event. The OnButtonClick
method would be defined in the code-behind file which contains another part of the class associated with the partial class generated by the XAML.
Let's suppose that the Button
we've been discussing is in a Window
subclass called MyWindow
. Here would be the code-behind file (MyWindow.xaml.cs):
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
}
void OnButtonClick( object sender, RoutedEventArgs e )
{
MessageBox.Show( "Click me again. That felt good." );
}
}
How the WPF Horse Race uses XAML
The WPF Horse Race application is almost entirely written in XAML. The application uses three C# files: the code-behind for the main Window
, a file for the RaceHorse
class, and another which contains some value converters (more on those in the article about data binding). The rest of the application is all in XAML.
I encourage you to explore the WPF Horse Race source files and check out what XAML looks like when it's being used to create a real program (as opposed to just a simple demonstration of it). The rest of the articles in this series will examine how that entire application works, but there is no substitute for just digging into the source files now and exploring how it works on your own.
External links
Prerequisites
XAML
General WPF Tips
History
- April 1, 2007 - Created the article.
- April 3, 2007 - Removed superfluous
ColumnDefinition
s from the Grid
in RaceHorseDataTemplate.xaml and updated the demo project download file. - April 18, 2007 - Fixed an incorrect statement about markup extensions. Originally I asserted that they are only used in conjunction with XML attributes, but they can be used with the property element syntax, as well.