What is eXtensible Application Markup
Language (or XAML)? For Windows Phone, XAML is used to design the user
interfaces (both the look and feel of applications), but it does quite a
lot more. The main concept to learn here is that XAML can be thought of
as a serialization format that works well with tools. It allows us to
declare the structure of a user interface. Declaring the interface in
this way makes it easy for tools to create the user interfaces and have
applications consume the files at runtime.
What do I mean by a serialization format? XAML is quite simple; let’s take a very basic piece of XAML:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBlock Text="Hello" />
<Rectangle Width="100"
Height="100"
Fill="Blue" />
</Grid>
</UserControl>
XAML is an XML file that obeys basic XML rules (e.g., single
top-level container, case sensitivity). In this file we are declaring a UserControl
root that contains a Grid
element that contains two elements (a TextBlock
and a Rectangle
).
This is the basic hierarchy of this simple user interface. When parsed,
this XAML document is used to create that same hierarchy in memory.
Literally, the name of the element ties itself to the name of a class.
So when the XAML is parsed, the UserControl
element informs the system to create a new UserControl
instance. To be used here all the classes must allow for empty constructors (in the .NET sense) so that the UserControl
class can be created. After it creates the UserControl
itself, it looks at its subelements (the Grid
) and creates that element as a child inside the UserControl
. Finally, it creates the TextBlock
and Rectangle
and places them as children inside the Grid
. When the TextBlock
is created, it sees the attribute (Text
) and calls the property setter of the new TextBlock
with the contents of the attribute. It does this with the multiple attributes of the Rectangle
as well. In this way it uses the XAML to build an in-memory object
graph that follows the same structure as the XAML. Understanding that
the XAML you are using is the basis for your runtime design is very
important in understanding how XAML works.
XAML Object Properties
Most objects’ properties you will set in XAML are simple and string-based:
<Rectangle Fill="Blue" />
Not all properties can be set using the simple, string-based syntax,
however. Under the covers, many properties (during XAML parsing) are
attempting to convert a string attribute to a property value (using a
special type of class called a TypeConverter
). For example, Fill
is a property that accepts a Brush
value, not a color. When Fill="Blue"
is parsed as XAML, a conversion is done between the string (i.e., “Blue”) and a brush called a SolidColorBrush
. For a more complex value type (like a Brush
), there is a verbose syntax for setting property values:
<Rectangle>
<Rectangle.Fill>
<SolidColorBrush Color="Blue" />
</Rectangle.Fill>
</Rectangle>
This verbose syntax is identical at runtime to the earlier example. By adding an element inside the Rectangle
whose name is the name of the object, a dot, and the name of the property (e.g., Rectangle.Fill
),
we can define the value for the property using XAML instead of being
stuck using just strings. Since not all complex property values can be
defined in such a way that a conversion can be made, this syntax allows
for property values to be set when the value is a complex type that
would be difficult or impossible to describe in a single string. For
example, let’s replace the SolidColorBrush
with a LinearGradientBrush
:
<Rectangle>
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="Blue" Offset="0" />
<GradientStop Color="White" Offset="0.5" />
<GradientStop Color="Blue" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
In this example, we can see that defining a fill by specifying the
colors and offsets not only would be difficult in a simple string, but
would make the XAML even harder to read. In this way, XAML allows you to
set very complex properties without having to invent conversions. You
will see how this is used in many different places in XAML as we
continue.
Understanding XAML Namespaces
Inside the root element are two namespaces. Namespaces in XAML are XML namespaces. The default namespace (xmlns
) declares that this is a XAML document. The second namespace (xmlns:x
) brings in several elements and attribute types that are all prefixed with the x
alias. So when you see x:Class
, that is a convention that is defined in the second namespace.
You can think of the namespace aliasing as similar to namespaces in
.NET. When you add a namespace, it brings in those new types of things
that can be described in XAML. Unlike .NET, though, you have to use an
alias (since all other namespaces are not the “default” namespace) and
then use that alias everywhere you want to refer to information from
that namespace. In the x
alias’s case, the alias here as
“x” is just a convention that XAML tends to use. In the XML namespace
sense, you can change the alias to whatever you want, but you would have
to change it everywhere it’s referenced as well. For example:
<UserControl foo:Class="WinningTheLottery.Sample"
xmlns="..."
xmlns:foo="...">
The alias is just that: an alias so that the parser can determine
which of the namespaces your element or attribute is from. When we
changed the name of the alias, it is what you would use to alias that
namespace in the rest of the document.
While these namespaces represent the basic XAML namespaces, you can
extend the XAML by using namespaces to bring in arbitrary .NET types as
well. If you define a namespace that points at a .NET namespace and
assembly, those types will also be available in the XAML:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid>
<TextBlock>
<TextBlock.Text>
<sys:String>Hello</sys:String>
</TextBlock.Text>
</TextBlock>
</Grid>
</UserControl>
In this example, the XAML “imports” the System
namespace that exists inside the mscorlib.dll
assembly. Once that .NET namespace is imported, all the types in that
namespace are creatable in the XAML. Any type that is created in XAML
must conform to the following rules:
• Has an empty, public constructor
• Has public properties
If any .NET objects follow these rules, they are creatable in XAML
(and therefore can be part of your initial object graph).
Naming in XAML
Unlike other platforms, XAML does not require that every object in
the XAML be specifically named. In fact, it is probably a bad idea to
name every object in the XAML. Naming objects in the XAML becomes
important once you need to refer to an object by name (e.g., from code
or via data binding). Naming objects in XAML takes the form of an
attribute that can be applied to most XAML elements: x:Name
. For example:
<UserControl x:Class="WinningTheLottery.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot">
<TextBlock Text="Hello"
x:Name="theTextBlock" />
<Rectangle Width="100"
Height="100"
Fill="Blue"
x:Name="theRectangle" />
</Grid>
</UserControl>
You will notice that the naming attribute starts with the x:
prefix (or alias). As was explained in the namespaces discussion, this means that attribute is available through the x
namespace that is included on the top of every XAML document (by
default). Once these objects are named, they will be available to other
XAML elements by name or via code . The names used here must be unique. Each name can occur only
once within a single XAML document. This simplifies the naming strategy
but also means there is no sense of naming scope (like HTML has).