- Elements and Attributes
- Namespaces
- Property Elements
- Type Converters
- Markup Extensions
- Children of Object Elements
- Mixing XAML with Procedural Code
- XAML Keywords
- Summary
Children of Object Elements
A XAML file, like all XML files, must have a single root object element. Therefore, it should come as no surprise that object elements can support child object elements (not just property elements, which aren’t children, as far as XAML is concerned). An object element can have three types of children: a value for a content property, collection items, or a value that can be type-converted to the object element.
The Content Property
Many classes designed to be used in XAML designate a property (via a custom attribute) that should be set to whatever content is inside the XML element. This property is called the content property, and it is just a convenient shortcut to make the XAML representation more compact.
Button’s Content property is (appropriately) given this special designation, so the following Button:
<
Button
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Content
=
"Stop
"/>
could be rewritten as follows:
<
Button
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation
">
Stop</
Button
>
Or, more usefully, this Button with more complex content:
<
Button
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation
">
<
Button.Content
>
<
Rectangle
Height
=
"10
"Width
=
"10
"Fill
=
"White
"/>
</
Button.Content
>
</
Button
>
could be rewritten as follows:
<
Button
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation
">
<
Rectangle
Height
=
"10
"Width
=
"10
"Fill
=
"White
"/>
</
Button
>
There is no requirement that the content property must be called Content; classes such as ComboBox and ListBox (also in the Windows.UI.Xaml.Controls namespace) use their Items property as the content property.
Collection Items
XAML enables you to add items to the two main types of collections that support indexing: lists and dictionaries.
Lists
A list is any collection that implements the IList interface or its generic counterpart. For example, the following XAML adds two items to a ListBox control whose Items property is an ItemCollection that implements IList<object>:
<
ListBox
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation
">
<
ListBox.Items
>
<
ListBoxItem
Content
="Item 1"/>
<
ListBoxItem
Content
="Item 2"/>
</
ListBox.Items
>
</
ListBox
>
This is equivalent to the following C# code:
Windows.UI.Xaml.Controls.ListBox
listbox =new
Windows.UI.Xaml.Controls.ListBox
(); Windows.UI.Xaml.Controls.ListBoxItem
item1 =new
Windows.UI.Xaml.Controls.ListBoxItem
(); Windows.UI.Xaml.Controls.ListBoxItem
item2 =new
Windows.UI.Xaml.Controls.ListBoxItem
(); item1.Content ="Item 1"
; item2.Content ="Item 2"
; listbox.Items.Add(item1); listbox.Items.Add(item2);
Furthermore, because Items is the content property for ListBox, you can shorten the XAML even further, as follows:
<
ListBox
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation
">
<
ListBoxItem
Content
=
"Item 1
"/>
<
ListBoxItem
Content
=
"Item 2
"/>
</
ListBox
>
In all these cases, the code works because ListBox’s Items property is automatically initialized to any empty collection object. If a collection property is initially null instead (and is read/write, unlike ListBox’s read-only Items property), you would need to wrap the items in an explicit element that instantiates the collection. The built-in controls do not act this way, so an imaginary OtherListBox element demonstrates what this could look like:
<
OtherListBox
>
<
OtherListBox.Items
>
<
ItemCollection
>
<
ListBoxItem
Content
=
"Item 1
"/>
<
ListBoxItem
Content
=
"Item 2
"/>
</
ItemCollection
>
</
OtherListBox.Items
>
</
OtherListBox
>
Dictionaries
A dictionary is any collection that implements the IDictionary interface or its generic counterpart. Windows.UI.Xaml.ResourceDictionary is a commonly used collection type that you’ll see more of in later chapters. It implements IDictionary<object, object>, so it supports adding, removing, and enumerating key/value pairs in procedural code, as you would do with a typical hash table. In XAML, you can add key/value pairs to any dictionary. For example, the following XAML adds two Colors to a ResourceDictionary:
<
ResourceDictionary
xmlns
=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
=
"http://schemas.microsoft.com/winfx/2006/xaml
">
<
Color
"
x:Key
=
"1
>White
</
Color
>
<
Color
"
x:Key
=
"2
>Black
</
Color
>
</
ResourceDictionary
>
This leverages the XAML Key keyword (defined in the secondary XML namespace), which is processed specially and enables us to attach a key to each Color value. (The Color type does not define a Key property.) Therefore, the XAML is equivalent to the following C# code:
Windows.UI.Xaml.ResourceDictionary
d =new
Windows.UI.Xaml.ResourceDictionary
(); Windows.UI.Color
color1 = Windows.UI.Colors
.White; Windows.UI.Color
color2 = Windows.UI.Colors
.Black;d.Add(
"1"
, color1);d.Add(
"2"
, color2);
Note that the value specified in XAML with x:Key is treated as a string unless a markup extension is used; no type conversion is attempted otherwise.
More Type Conversion
Plain text can often be used as the child of an object element, as in the following XAML declaration of SolidColorBrush:
<
SolidColorBrush
>White
</
SolidColorBrush
>
This is equivalent to the following:
<
SolidColorBrush
Color
=
"White
"/>
even though Color has not been designated as a content property. In this case, the first XAML snippet works because a type converter exists that can convert strings such as "White" (or "white" or "#FFFFFF") into a SolidColorBrush object.
Although type converters play a huge role in making XAML readable, the downside is that they can make XAML appear a bit “magical,” and it can be difficult to understand how it maps to instances of objects. Using what you know so far, it would be reasonable to assume that you can’t declare an instance of a class in XAML if it has no default constructor. However, even though the Windows.UI.Xaml.Media.Brush base class for SolidColorBrush, LinearGradientBrush, and other brushes has no constructors at all, you can express the preceding XAML snippets as follows:
<
Brush
>White
</
Brush
>
The type converter for Brushes understands that this is still SolidColorBrush. This might seem like an unusual feature, but it’s important for supporting the ability to express primitive types in XAML, as demonstrated in “The Extensible Part of XAML.”