#93 – Specifying Markup Extensions Using Property Element Syntax

Markup extensions are typically expressed directly as property values using braces–{, }. (Property attribute syntax).

 <Button Name="btnOne" Background="{StaticResource aliceBrush}" Content="Dum" Height="23" Width="75" />

But a markup extension can also be expressed using property element syntax.  The XAML fragment below is equivalent to the one listed above.

 <Button Name="btnOne" Content="Dum" Height="23" Width="75">
     <Button.Background>
         <StaticResource ResourceKey="aliceBrush"/>
     </Button.Background>
 </Button>

#92 – Markup Extensions

When property values are specified in XAML, the property can get its value in one of three different ways:

  • Property assigned a literal string value
  • Property assigned a value by a type converter, converted from a literal string
  • Property assigned based on a markup extension

A markup extension is special syntax that dictates where a property should get its value.  Markup extensions are specified using braces–{, }.

 <!-- Background property set using type converter -->
 <Button Background="Red" Content="Dum" Height="23" Width="75" />
 <!-- Background property set using the StaticResource markup extension -->
 <Button Background="{StaticResource blueBrush}" Content="Dee" Height="23" Width="75" />

The most common markup extensions that you’ll encounter in WPF include:

  • StaticResource – set property to object in resource dictionary
  • DynamicResource – set property to resource, loading at run-time
  • Binding – set property using data binding
  • TemplateBinding – placeholder in a template, value comes from the object using the template

#87 – Type Converters

In XAML, you often set a property value by specifying a single string value.  However, when setting the value of a property that is not a System.String, the specified string must be converted into the proper type.  This is done automatically by the XAML parser using a type converter.

For example, in the example below, we set the background color of a button by specifying the string “Azure”.

 <Button Content="Click Me" Background="Azure" Height="25" Width="50" />

Because the Button.Background property is of type System.Windows.Media.Brush, the parser must convert the string “Azure” to a Brush object.

The XAML parser will attempt to convert the value if either:

  • The property in question has a TypeConverter attribute
  • The class that implements the property’s type has a TypeConverter attribute

For the Button.Background property, the value is converted from a string to a SolidColorBrush by the System.Windows.Media.BrushConverter class.

#86 – The Class Attribute Points to Your Code-Behind

The root element in a XAML file can have an x:Class attribute that specifies how to find the code-behind associated with the class being defined in the markup.

Examples:

 <Application x:Class="WpfApplication1.App"

or

 <Window x:Class="WpfApplication1.MainWindow"

When you build your project, the XAML is compiled and two things occur: 1) the XAML is converted into tokenized binary BAML; and 2) code is generated (e.g. C#) which will serve as a partial class that matches the partial class for your code-behind.  Notice that the value of the Class attribute matches the name of the corresponding class.

So in a default project, after building, you’ll get the following code files:

  • Main application
    • App.g.cs – code generated from App.xaml
    • App.xaml.cs – your code-behind for App class
  • Main window
    • MainWindow.g.cs – code generated from MainWindow.xaml
    • MainWindow.xaml.cs – your code-behind for MainWindow class

#84 – Store Reusable Objects in a Resource Dictionary

Assume that you want to set the background color for two buttons to the same color.  You could specify a SolidColorBrush for each button’s Background property :

 <Button Name="btnOne" Content="Dum" Height="23" Width="75" Click="Button_Click">
     <Button.Background>
         <SolidColorBrush Color="AliceBlue"/>
     </Button.Background>
 </Button>
 <Button Name="btnTwo" Content="Dee" Height="23" Width="75" >
     <Button.Background>
         <SolidColorBrush Color="AliceBlue"/>
     </Button.Background>
 </Button>

In doing this, you created two different brushes.  But you could have been more efficient by creating a single brush, storing it in the resource dictionary of the parent window and then referencing the common brush when specifying the buttons’ Background property :

 <Window.Resources>
     <SolidColorBrush x:Key="aliceBrush" Color="AliceBlue"/>
 </Window.Resources>
 <StackPanel Name="spContainer">
     <Button Name="btnOne" Background="{StaticResource aliceBrush}" Content="Dum" Height="23" Width="75" Click="Button_Click" />
     <Button Name="btnTwo" Background="{StaticResource aliceBrush}" Content="Dee" Height="23" Width="75" />
 </StackPanel>

We created the common brush in the window’s resource dictionary–specified by the Resources property–and then referred to it in each Button using the StaticResource markup extension and a key.

#83 – Collection Syntax for Read-Only Vs. Read-Write Properties

When using the XAML collection syntax for a collection-based property that is read/write, the inclusion of an object element representing the collection object is optional.

E.g. Because FrameworkElement.Resources is read/write, we can list a series of resources using either of the following forms.

 <!-- Create new ResourceDictionary, assign to Resources property -->
 <Window.Resources>
     <ResourceDictionary>
         <SolidColorBrush x:Key="redBrush" Color="Red"/>
         <SolidColorBrush x:Key="indigoBrush" Color="Indigo"/>
     </ResourceDictionary>
 </Window.Resources>

 <!-- Omit ResourceDictionary, use collection syntax, new resources added to existing collection -->
 <Window.Resources>
     <SolidColorBrush x:Key="redBrush" Color="Red"/>
     <SolidColorBrush x:Key="indigoBrush" Color="Indigo"/>
 </Window.Resources>

However, for read-only collection properties, because you can’t create a new instance of the collection and assign it to the property, you must use the collection syntax, omitting the object element for the collection.

 <StackPanel.Children>
     <!-- Children property is read-only, so we can't include UIElementCollection element here -->
     <Button Content="Button" Height="25" Width="50" />
<ComboBox Height="23" Width="120" />
 </StackPanel.Children>

#82 – How XAML Handles Whitespace

In general, embedded spaces and line feeds in a XAML file are ignored.  You can normally include spaces or line feeds between consecutive items.  Here are some guidelines:

  • You must have at least one space preceding each XAML attribute
  • You must not have any whitespace following the open angle bracket ‘<‘ in an element tag
  • You must not have any whitespace between the ‘/’ and ‘>’ characters in a self-closing element
  • Whereever a namespace prefix is used, with the ‘:’ character, you must not have whitespace on either side of the ‘:’
  • When a property value is expressed as text within quotation marks and it represents textual content, embedded whitespaces and line feeds are preserved.  (E.g. Embedded line feed in a button label)
  • When text is used as a value for a content property, i.e. not in quotation marks
    • All leading and trailing whitespace is removed  (i.e. the string starts with the first non-whitespace character)
    • Internal whitespace is converted to a single space

#81 – XAML Is Case Sensitive

XAML is case sensitive because the corresponding .NET objects, as well as their properties and event names, are also case sensitive.

The XAML below is fine (will compile):

 <Button Content="Click Me" Height="23" Width="75" Click="button1_Click" />

Changing the case of Button results in a compilation error:

 <BUTTON Content="Click Me" Height="23" Width="75" Click="button1_Click" />

#80 – Content Properties and Collection Syntax Express UIElement Containment

Using both a content property and the collection syntax is quite common in XAML and often expresses containment of a collection of UIElement objects in a parent container.

For example, the StackPanel is a parent control, containing a number of child controls:

 <StackPanel>
     <Label Content="A label" Height="28" />
     <Button Content="Click Me" Height="23" />
 </StackPanel>

In this example, containment is expressed by listing the child controls contained in the StackPanel as child elements in XAML.

This containment shorthand is possible for two reasons:

  • StackPanel‘s content property is Children, an UIElementCollection
  • We can specify the members of the UIElementCollection using collection syntax, by listing its members

All containers that inherit from System.Windows.Controls.Panel have Children as their content property–including Grid, StackPanel, Canvas, WrapPanel, etc.

#79 – Content Properties for Common WPF Types

Here is a list of the content properties for some common WPF types.  You can set values for these properties in XAML using one or more child elements directly, rather than having to use the property element syntax.

E.g. Because Text is the content property for a TextBox, you can specify a value for Text as a child element of the TextBox element:

 <TextBox Height="23" Width="120">
     Some text...
 </TextBox>

Here is the list of some common WPF types and their content properties:

  • Button – Content
  • CheckBox – Content
  • ComboBox – Items
  • Grid – Children
  • GridView – Columns
  • GroupBox – Content
  • Label – Content
  • ListBox – Items
  • ListView – Items
  • Page – Content
  • Panel – Children
  • StackPanel – Children
  • TextBox – Text
  • TreeView – Items
  • Window – Content

For a more complete list, see Building A List of Types That Have Content Properties.