What You’ll Learn in This Hour:
How properties can be represented as elements
Namespaces
XAML, or Extensible Application Markup Language, is an XML-based language created by Microsoft. It’s as fundamental to WPF as HTML is to web development.
XAML (pronounced zammel) is the language used for creating user interfaces in WPF. It’s an XML-based markup language similar to HTML, MXML, or XUL. XAML has applicability well beyond defining user interfaces. In fact, it’s even possible to represent data with XAML, such as an array of strings or an instance of object. XAML is also used by Windows Workflow Foundation (WF) for defining workflows. In the most general sense, XAML is a language for serializing .NET object instances into a human readable format.
Even though Visual Studio 2008 provides a WYSIWYG editor with drag-and-drop support for producing and manipulating XAML, you will often need to edit your markup directly. We’ll be writing our XAML by hand for most of the book. The default file extension is .xaml
.
XAML can be either compiled or interpreted, depending on how it is used. Some features, such as embedding C# or VB code in XAML, work only when the XAML is compiled. When you create a WPF application with Visual Studio, the XAML used in the application is compiled into the resulting executable. However, you can create .xaml
files that are meant to be interpreted on-the-fly (no compilation is involved). These XAML files are usually hosted in a web browser.
Let’s create a simple “hello world” XAML application. You’ll need to have the .NET Framework 3.5 installed to do this exercise. It’s installed as part of Visual Studio 2008.
Open your favorite text editor, such as Notepad.
Create a plain text document and enter the following:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <TextBlock Text="Hello World!" /> </Page>
Save the text file and name it HelloWorld.xaml
.
Double-click the newly created file, and it should open in a web browser. If another application has been mapped to .xaml
, you will need to launch the browser first (either Internet Explorer 7 or Firefox will do) and drag the file into the browser.
Congratulations, you’ve just created your first WPF application using XAML. HelloWorld.xaml
is an example of interpreted XAML because we never compiled the application to an executable. XAML-only applications are rather limited, and in real life you’re much more likely to use XAML in concert with C# or VB.
In HelloWorld.xaml
, notice that the root element is a Page
tag. Some other possibilities exist, most frequently the Window
tag, but we’ll get to that shortly. When authoring XAML, your root element always defines two namespaces. The default namespace is specifically mapped to WPF, whereas the prefix x:
is for XAML’s more generic features. Remember, XAML can be used to represent all kinds of data; we used the default namespace to say that we are representing data about WPF. The x
namespace is representing a broader context. That may sound a little backward, but you’ll quickly find that you don’t use the x
namespace as much as the default one. If this doesn’t make sense, don’t worry about it for the moment. It won’t stop you from using XAML, and we’ll review it again later. Just know that these namespace aliases are the convention adopted by Microsoft, and you’ll see it in all the examples and documentation.
Namespaces in XML are often confusing if you have not worked with them before. Namespaces in XML serve the same function as namespaces in .NET; they provide a scope for unique names.
It’s similar to the idea of having two people named John Smith. To distinguish between them, you might call one John Smith from Surrey and the other John Smith of Boston. Including the place where they are from is analogous to the namespace. When two things are named the same, and we can’t tell them apart, it is called a naming collision.
The xmlns
attribute is used to map a local name (or alias), such as x
, to the actual namespace, which is specified as a URI. Individual elements or tags that reside in the namespace use the local name as a prefix in their tags.
The namespace tells the XML parser how the elements in the document should be interpreted.
As a general rule, an element in XAML is an instance of an object and attributes are properties on that object. The markup in Listing 2.1 is for a simple button on a page.
The root element corresponds to an instance of Page
, more specifically System.Windows.Controls.Page
. Page
, and everything else in the System.Windows.Controls
namespace, is a WPF control.
The Button
element corresponds to an instance of the class System.Windows.Controls.Button
. In turn, the attributes on the Button
element represent properties on an object instance. Thus, we are setting the values for the properties of Width
, Height
, Background
, and Content
.
There is also the x:Name
attribute, which breaks the rule here. x:Name
is not a property on the Button
class. Instead, it’s a special attribute that provides a unique identifier to the object for accessing it in code. It is the same as creating a variable of type Button
with the name blueButton
. The Button
element in the preceding XAML is equivalent to the following C#:
Button blueButton = new Button(); blueButton.Width = 100; blueButton.Height = 40; blueButton.Content = "Click Me"; blueButton.Background = new SolidColorBrush(Colors.Blue);
The Background
property is a little more complex than the others. We’ll talk about that in a second. It is important to understand that any XAML element you want to reference, in code or elsewhere in the XAML, must have a unique value for x:Name
. Providing a value from x:Name
is like creating a variable and then setting the variable to the instance of the object.
The Button
class has a Name
property, and interestingly enough, setting a value for x:Name
also sets the same value for Name
. In fact, for any object that has a Name
property, the two attributes can be used interchangeably. This was very confusing for us when we first started working with XAML.
It’s pretty easy to get into trouble using the Name
property, though, and unless you have a specific need, we recommend sticking with x:Name
. It’s the convention that is generally adopted.
On the Button
class, Width
and Height
are simple value types. WPF converts the string value 100
to a double
implicitly. However, many properties on controls are not simple value types. Some properties are objects that have lots of properties themselves, which could also be complex types. In our example, the Background
property on Button
is of type Brush
. In the XAML, we are able to simply say Blue
and it works.
There are many places in XAML where commonly used types, such as SolidColorBrush
, can be represented by a simple string value that WPF just knows how to handle. In the case of SolidColorBrush
, you can provide any named color, as found on the System.Windows.Media.Colors
class, or you can provide a hexadecimal representation of the color similar to those you would use in HTML or CSS. Both of the following XAML snippets are equivalent:
<Button Background="#FF0000FF" /> <Button Background="Blue" />
In some situations, however, this shorthand is not sufficient for telling WPF what you want. In those cases we can use property element syntax. Property element syntax is an alternative syntax used for providing values for complex types. Instead of setting the Background
property using an attribute, we can use a child element. The following snippet demonstrates using this alternative syntax for setting the background to blue:
<Button> <Button.Background> <SolidColorBrush Color="Blue" /> </Button.Background> </Button>
The child element is referred to as a property element. Property elements take the form of <ClassName.PropertyName />
. That is, the first part of the element’s name is the class name, followed by a dot, followed by the property’s name. The content of the child element is the value we want to set. When using a property element, we need to be more explicit and tell WPF that we want the value to be an instance of SolidColorBrush
with the Color
property set to blue. This syntax can become very verbose, but in many situations it is the only way to provide the exact value that you desire.
It’s preferable to use the shorthand when possible. Succinct markup is easier to read and it makes the intention of the XAML clearer.
Many of the WPF controls that you will encounter have a property named Content
. Content
is a special property. In Listing 2.1, we set the Content
of a Button
to a string value, Click Me
. However, you can also set the Content property implicitly using a child element. For example, the following XAML elements are equivalent:
<Button Content="Click Me" /> <Button>Click Me</Button>
Both buttons will be rendered the same in WPF. What’s exciting is that Content
is actually of type object
. That means that we can make a button’s content much more than just a simple string. For example, perhaps we want to draw a yellow circle inside our button. You could use the following XAML:
<Button> <Ellipse Width="24" Height="24" Fill="Yellow" /> </Button>
You can always set the Content
property explicitly, too:
<Button> <Button.Content> <Ellipse Width="24" Height="24" Fill="Yellow" /> </Button.Content> </Button>
However, doing so is more verbose and does nothing to improve the readability or maintainability of your code. Furthermore, the convention of setting the Content
property implicitly is almost universally adopted.
If you go back to Listing 2.1 one more time, you will notice that our Button
element is actually the value for the Page.Content
property.
Sometimes we need to specify values in our markup that are either difficult to express in XAML or outside the scope of the XAML processor. XAML has a feature called markup extensions and it allows us to handle these awkward situations.
For example, suppose we have a specific color we want to use as the background for several buttons in a WPF application. We could set the Background
property on each of the buttons to use the same color, but it would become tedious if we ever needed to change that color. With WPF, we can store the color with a lookup key in an application’s resources. (We’ll discuss this concept in depth in Hour 14, “Resources and Styles.”) Now we can set the background of the buttons to the color we stored in the resources. If we want to change the color, we need do so in only one place. That’s a lovely scenario, but how would we handle this in XAML? We would use a markup extension.
In the preceding scenario, the XAML with the markup extension might look like this:
<Button Background="{StaticResource ResourceKey=myColor}" Content="Click Me" />
Markup extensions are indentified by the presence of curly brackets ({}). The first word in the markup extension tells WPF what kind of extension it is. The name of the extension is optionally followed by a set of named parameters. In this case, the extension is for retrieving a shared resource from a library of resources. The name of the extension is StaticResource
, and we provide a value of myColor
for the ResourceKey
parameter. Many extensions have a default parameter. You don’t have to explicitly reference a default parameter. You are allowed to omit the parameter name and the equal sign. For example, we could restate the snippet without ResourceKey=
:
<Button Background="{StaticResource myColor}" Content="Click Me" />
ResourceKey
is the default parameter for StaticResource
.
In some cases, you will have more than one parameter. If you do, you must separate name/value pairs with commas. The general pattern is this:
{ExtensionName Param1=Value1, Param2=Value2, Param3=Value3}
The most frequent mistake in dealing with markup extensions is to include quotation marks around the values. You are not allowed to have quotation marks between the curly brackets. This confuses the parser. It also means that parameter values cannot have whitespace.
Many markup extensions are built in to WPF, and you can even write your own (however, it is not common to do so).
We’ll cover specific extensions as they become relevant throughout the book; however, Table 2.1 has a very brief summary of the most significant extensions. Don’t be too concerned about understanding these extensions right now; they will make sense in context.
Table 2.1. Common Markup Extensions in WPF
Name | Description |
---|---|
| The extension used for binding data. This is discussed in Hour 6, “Introducing Data Binding.” |
| This is used for retrieving data from an application’s resources. Static resources are not expected to change while the application is running. We cover this in Hour 14. |
| Similar to |
| Used for specifying a null value in XAML. We’ll show one way to use this in Hour 23, “Animation,” although it has many uses. |
| This extension is used for supplying a |
| This allows you to define an array of objects in XAML. We’ll demonstrate the use of this in Hour 15, “Digging Deeper into Data Binding.” |
Understanding XAML is essential to working with WPF. Although it is possible to write a WPF application without XAML, it is awkward and clumsy. XAML is very flexible, and a lot of traditional programming tasks can now be handled with XAML. Like WPF in general, you won’t be able to master XAML overnight. Even developers who have worked with the language for some time often discover features they were unaware of.
The goal of this hour was to equip you with a foundational knowledge of XAML and how it is used. We will continue to build on that foundation in the remaining hours.
18.191.234.150