New book: XAML Developer Reference

We’re pleased to announce that the new Microsoft Press book XAML Developer Reference (ISBN 978-0-7356-5896-7, 340 pages) is now available for purchase!

This book covers XAML from the ground up for both Windows Presentation Foundation and Silverlight development—and of course, because XAML is a foundational technology in building Windows 8 applications, learning the information here will be useful for a long time to come.

You’ll discover practical ways to build rich, interactive user interfaces with data integration capabilities and support for multimedia, graphics, and animation. This hands-on guide is ideal for Microsoft .NET developers and web designers alike.

Written by two XAML experts, Mamta D and Ashish Ghoda, this book covers all the basic XAML elements, their properties and event systems, use of templates, positioning, 2D and 3D graphics, markup extensions, data binding, and much more.

Read the complete Chapter 4, “Markup Extensions and Other Features,” below to get a good feel for the level of detail in this book.

 
  clip_image001

Chapter 4 - Markup Extensions and Other Features

In this chapter:

  • Markup Extensions in XAML
  • Built-In XAML Extensions
  • XAML Markup Extensions in WPF and Silverlight
  • Escape Sequences
  • Custom Markup Extensions
  • Type Converters versus Markup Extensions
  • XAML Services
  • Security in XAML
  • Summary

You’ll see a great deal more about data binding in Chapter 8, “Data Binding,” including several methods and approaches for binding controls to data, but for now, two key extensions crucial to the implementation of data binding are the StaticResource and Binding extensions. These extensions, also called markup extensions, are placeholders to resolve a property at run time. Without the use of the StaticResource and Binding markup extensions, the process of binding would be very cumbersome indeed.

XAML and the WPF and Silverlight implementations of XAML alsosupportseveral other markup extensions that can be used for tasks besides data binding.

1) Markup Extensions

XAML, being an XML-based language used to declare objects and the relationships between them, is simple by nature. However, this simplicity comes at a cost—XAML can be quite long-winded at times.

XAML lacks any inherent or built-in knowledge of common artifacts such as arrays, static members of a class, data binding, and so forth. Because XAML can be an integral part of application development, developers need some way to express information about such artifacts in it. Additionally, to be a long-lasting format, XAML had to be extensible.

To provide a solution for all these issues, Microsoft introduced the concept of markup extensions. Using markup extensions, you can extend XAML in an elegant way; you can set any property that can be set in XAML using attribute syntax. Attribute syntax can provide reference values for a property even if that property does not support an attribute syntax for direct object instantiation.

For example, the following code makes use of attribute syntax to set the value of the Style property. The Style property takes an instance of the Style class, a reference type that typically could not be specified within an attribute syntax string. But here, the attribute references a specific markup extension, StaticResource. When that markup extension is processed, it returns a reference to a style which was instantiated earlier as a keyed resource.
<Page.Resources>
<SolidColorBrush x:Key="Test" Color="Pink"/>
<Style TargetType="Border" x:Key="MyBorder">
<Setter Property="Background" Value="Gray"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style='{StaticResource MyBorder}'>
</Border>
</StackPanel>

The System.Windows.Markup namespace contains the definitions for most of the markup extension classes. These class names end with the suffix Extension; however, when you use them in XAML, you can omit the Extension suffix. For example, in XAML you represent the NullExtension markup class as x:Null. Markup extensions may also support parameters, which you specify as a comma-delimited list. Markup extension classes typically have default constructors.

The syntax of a markup extension is an opening brace ( { ), followed by the markup extension name, optionally followed by parameters to the markup extension, and ending with a closing brace ( } ). When the XAML compiler or parser encounters an attribute enclosed in braces, it automatically recognizes it as a markup extension.

Although WPF and Silverlight commonly support various markup extensions, some extensions are supported only by WPF. In contrast, Silverlight-only extensions are rare.

You can also create a custom markup extension by deriving from the MarkupExtension class.

2) Built-In XAML Markup Extensions

Some markup extensions are built in to XAML; that is, they are a part of the native XAML vocabulary. These are not specific to the WPF implementation of XAML; they are features of XAML as a language and are implemented in the System.Xaml assembly.

The built-in XAML markup extensions are typically prefixed with x: and enclosed within braces, like other markup extensions. However, not all language features that start with x: are markup extensions. For instance, the x:Class name that you use with an element is an attribute, not a markup extension. Similarly , x:Key and x:Name are attributes.

Note There are no built-in markup extensions for string manipulation in XAML.

Some of the built-in XAML markup extensions are described in detail in the following sections.

i) x:Null

Supported By

WPF

Yes

Silverlight

Yes

Use this markup extension to specify a null value. This markup extension is supported by both WPF and Silverlight. In some scenarios you may want to assign a null value to an element, style, or similar item. The x:Null markup extension proves useful in such scenarios.

Here’s an example. Suppose you have defined a style for buttons in a Silverlight application. You now want to prevent a specific Button from using that style. To do that, use the markup <Button Style=”{x:Null} “ Name=btnOK” ></Button> . Assigning the x:Null markup extension prevents the button from using that style.

<Grid x:Name="LayoutRoot" Background="Beige">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="4"></Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Name="btnOK" Content="OK" Height="100" Width="200"/>
<Button Grid.Row="1" Name="btnDone" Content="Done" Height="100" Width="200"/>
<Button Grid.Row="2" Content="Bye" Style='{x:Null}' Height="100" Width="200"/>
</Grid>

As a result of this markup, two buttons will use the predefined Button style, but the third button will not have any style, because its style has been assigned the {x:Null} markup extension, as shown in bold.

Figure 4-1 shows the outcome of this markup.

clip_image003

Figure 4-1 Using the X:Null markup extension

Note It’s important to remember that setting a value to null is not the same as not setting it at all. Dependency properties in WPF obtain their value from a number of sources; therefore, setting a local value takes precedence over values sourced from elsewhere, such as an animation or a style.

Assigning x:Null to the background of an element such as Button is different from assigning Transparent to the background. Consider the code shown here:

<Button Height="200" Width="200" Background="{Transparent}"
BorderBrush="Blue" BorderThickness="3" Click="Button_Click"></Button>

This code works as expected and renders a transparent button with a blue border. The button is clickable, and when a user clicks the button, you could perform some action.

However, if you change the Background to x:Null as shown here, the rendered button will not be clickable.

<Button Height="200" Width="200" Background="{x:Null}" BorderBrush="Blue"
BorderThickness="3" Click="Button_Click"></Button>

The reason for this is that in the first case, the background was set to a transparent brush. Even though the brush is transparent, it is still an instance of SolidColorBrush with the color SystemColors.Transparent. However, in the second case, the brush is set to null, which means there is no brush at all, which renders the button as unclickable.

ii) x:Array

Supported By

WPF

Yes

Silverlight

No

This markup extension is supported by WPF but is not supported in Silverlight. In XAML 2009, x:Array is defined as a language primitive rather than a markup extension.

x:Array lets you to create simple arrays using XAML syntax, as shown here:

<x:Array Type="sys:String" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib" >
<sys:String>Orange</sys:String>
<sys:String>Blue</sys:String>
<sys:String>Green</sys:String>
<sys:String>Pink</sys:String>
</x:Array>

A typical use of this markup extension would be to provide a list of contents for a ListBox or ComboBox as shown here:

<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Background="PaleGreen"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsSource>
<x:Array Type="sys:String" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib" >
<sys:String>Orange</sys:String>
<sys:String>Blue</sys:String>
<sys:String>Green</sys:String>
<sys:String>Pink</sys:String>
</x:Array>
</ListBox.ItemsSource>
</ListBox>

Figure 4-2 shows the outcome of this markup.

clip_image005

Figure 4-2: Using X:Array with a ListBox

iii) x:Reference

Supported By

WPF

Yes

Silverlight

No

This markup extension is not supported in Silverlight. In WPF, it is used to reference a previously declared element. Here’s an example: A Label used to prompt for customer name must set the focus to a text box that will accept the customer name when a user presses a specified access key assigned to the Label. In XAML 2006 and earlier, you could accomplish this explicitly by using Binding and ElementName to perform the binding.

<TextBox Name="customerName" Text="" Height="24" Grid.Row="0" Grid.Column="1"
Margin="20,40,238,40"></TextBox>
<Label Target='{Binding ElementName=customerName}' Height="27" Width="117" Grid.Row="0"
Grid.Column="0">_Customer Name:</Label>

The underscore in the Label name defines the subsequent character as the access key. In this case, pressing C at run time will set the focus to the customerName text box.

Using the x:Reference markup extension, you can now write the same code as the following:

<TextBox Name="customerName" Text="" Height="24" Grid.Row="0" Grid.Column="1"
Margin="20,40,238,40"></TextBox>
<Label Target='{x:Reference customerName}' Height="27" Width="117" Grid.Row="0"
Grid.Column="0">_Customer Name:</Label>

Thus, using x:Reference, the code becomes more concise and simpler. Although this example was simple, you can use the x:Reference markup extension in more complex scenarios, too.

Note When using {x:Reference <controlname>} as the Target of a WPF Label, the Visual Studio designer throws an InvalidOperationException exception with the message "Service provider is missing the INameResolver service." The project will compile and execute without any issues, but the Design canvas where the x:Reference appears will be disabled because of the exception. As of this book’s writing, this is a known issue and should be resolved sometime in the future.

iv) x:Static

Supported By

WPF

Yes

Silverlight

No

This markup extension produces static values. The values come from value-type code entities that are not directly the type of a target property's value, but can be evaluated to that type. The x:Static markup extension is evaluated at run time when the XAML is actually loaded.

For example, you could use it as shown here:

<TextBlock Text=”Demo!” >
<TextBlock.Background>
<SolidColorBrush Color=”{x:Static SystemColors.ControlColor}” />
</TextBlock.Background>
</TextBlock>

The preceding code uses a built-in system type ControlColor defined in the SystemColors assembly and assigns it to the Color property of the brush used to fill the TextBlock background.

The following example assigns the Text property of a TextBlock to the value defined in a custom assembly. This assembly is first referenced in the XAML markup with a prefix; later, that prefix is used to refer to the type:

<TextBlock Text=”{x:Static Member=”local:MyClass.Header}” Grid.Row=”0” />

In the preceding example, local was previously defined as a namespace prefix using this syntax:

xmlns:local=”clr-namespace:WPFApp”

The code-behind class defines a custom type named MyClass, which contains a static readonly property named Header.

public class MyClass
{
public static readonly string Header = “DevCon 2011”;
}

In this example, specifying Text=”{local:MyClass.Header}” without using the x:Static markup extension would result in a compiler error. The only way you can access the static property defined in the MyClass class from markup is by using the x:Static markup extension.

This extension can also be useful in scenarios where you want to specify a base style that is defined as a class property:

<StackPanel>
<StackPanel.Resources>
<ResourceDictionary>
<Style TargetType="Button" BasedOn=”{x:Static local:MyStyle.BaseStyle}” />
</ResourceDictionary>
</StackPanel.Resources>
</StackPanel>

In the preceding XAML, MyStyle is a class that defines a static property named BaseStyle of type Style.

v) x:Type

Supported By

WPF

Yes

Silverlight

No

This markup extension is supported only in WPF, not in Silverlight. It is used to specify the target type for an element—for example, while creating a style. The functionality of this markup extension is identical to TargetType in that you can use either interchangeably. The only scenario where using the x:Type extension makes more sense is when you’re specifying custom objects and want to set the type explicitly.

Here’s a simple example of using this extension:

<Grid x:Name="LayoutRoot" Background="Beige">
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Red"></Setter>
<Setter Property="BorderThickness" Value="7"></Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Name="btnOK" Content="OK" Height="100" Width="200"/>
<Button Grid.Row="1" Name="btnDone" Content="Done" Height="100" Width="200"/>
</Grid>

Note that in the preceding code, you could have easily omitted {x:Type} in the TargetType declaration without making any difference to the output. That is, you could write TargetType="Button” in place of TargetType="{x:Type Button}".

3) XAML Markup Extensions Used in WPF and Silverlight

The following markup extensions are a part of the XAML language and are intrinsic language features:

· Binding This markup extension binds the values of two properties together. It is most commonly used in data-binding scenarios to bind the value of a FrameworkElement instance to a specific piece of data. For example, you can bind a customer name to a text box.

· StaticResource This markup extension is used to implement a one-time lookup of a resource entry. The resource entry could be defined in the resources section of a container control such as a Grid, a StackPanel, and so forth.

· DynamicResource This markup extension is used to implement lookup of a resource entry dynamically at run time.

· TemplateBinding This markup extension is used to bind a property of a control template to a dependency property of the control.

You’ll see numerous examples of these extensions discussed in Chapter 8. Apart from specifying property values using markup extensions, you can use two other approaches to assign property values:

· Property assigned a literal string value

· Property assigned a value by a type converter, converted from a literal string

For example, the following markup demonstrates how property element syntax can be used to refer to a StaticResource without using markup extensions:

<Binding.ValidationRules>
<StaticResource ResourceKey="IsValidRule"/>
</Binding.ValidationRules>

4) Escape Sequences

In some scenarios you may need to include a pair of braces as a literal in your code as a string text. Typically, XAML processors use an open brace ({) to indicate the start of a markup extension sequence. So when the open brace is encountered, the XAML processor assumes that a markup extension follows. To override this behavior and specify an escape sequence, use a pair of empty braces. The two-brace escape sequence ({}) identifies braces in the subsequent text as literal characters.

For example, the following markup shows an escape sequence for an XML namespace that appears at the start of a XAML attribute value:

<StackPanel>
<TextBlock Text="{}{https://www.contoso.com}" />
</StackPanel>

Here, you want to use the namespace https://www.contoso.com/ and the braces together as a literal, so you specify an escape sequence by using a pair of empty braces. The output produced will include the braces and will display {https://www.contoso.com} .

5) Custom Markup Extensions

Custom markup extensions are useful in scenarios where you need the extension to provide functionality or behavior that is beyond the scope of existing built-in markup extensions.

In earlier versions of Silverlight, you could not create custom markup extensions, but Silverlight 5 added support for them. You create a custom markup extension by extending the MarkupExtension class or the IMarkupExtension interface.

One of the biggest issues in data binding with Silverlight is that there is no support for an ObjectDataProvider class. In some instances, such as when binding to XML data, the lack of support for this class proves to be a huge drawback.

Until Silverlight 5, for example, there was no way to write something like the markup shown here, which binds an XML file and an element within it to a UI element in a Silverlight application declaratively:

<ListBox ItemsSource="<some mechanism> Source=Employee.xml, Path=/Manager/FirstName}"

You could parse the XML entirely in code in a number of ways—but you had no way to perform a declarative binding in XAML. This is where the custom markup extension feature introduced in Silverlight 5 can come to the rescue.

Use the following steps to create and use such an extension:

1. Create a Silverlight 5 application named XMLBinderDemo.

2. Add an XML file named Employee.xml to the application that has the following contents:

<?xml version="1.0" encoding="utf-8" ?>
<Employee>
<Manager FirstName="Jonathan" LastName="Bates" />
<Manager FirstName="Bill" LastName="Buxton" />
<Manager FirstName="Patrick" LastName="Kerr" />
<Engineer FirstName="Wei" LastName="Han"/>
</Employee>

3. Add a reference to the System.Xml.Linq assembly.

4. Add a class named XMLBinderExtension to the application.

5. Add the following code to the class:

namespace XMLBinderDemo
{
public class XMLBinderExtension : MarkupExtension
{
public string Source { get; set; }
public string Path { get; set; }
private static List<string> Parse(string file, string path)
{
XDocument xdoc = XDocument.Load(file);
string[] text = path.Substring(1).Split('/');
string desc = text[0].ToString();
string elementname = text[1].ToString();
List<string> data = new List<string>();
IEnumerable<XElement> elems = xdoc.Descendants(desc);
IEnumerable<XElement> elem_list = from elem in elems
select elem;
foreach (XElement element in elem_list)
{
String str0 = element.Attribute(elementname).Value.ToString();
data.Add(str0);
}
return data;
}
/// <summary>
/// Overridden method that returns the source and path to bind to
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
public override object ProvideValue(IServiceProvider serviceProvider)
{
if ((Source != null) && (Path != null))
return Parse(Source, Path);
else
throw new InvalidOperationException("Inputs cannot be blank");
}
}
}

6. Finally, you can write the XAML markup as shown here:

<UserControl x:Class="XMLBinderDemo.MainPage"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:XMLBinderDemo"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" >
<Grid x:Name="LayoutRoot" Background="White">
<ListBox ItemsSource="{local:XMLBinderExtension Source=Employee.xml,
Path=/Manager/FirstName}" Height="200" Width="200" Background="Beige" />
</Grid>
</UserControl>

The XMLBinderExtension class derives from the MarkupExtension class defined in the System.Windows.Markup assembly. The MarkupExtension class provides a base class for XAML markup extension implementations.

The ProvideValue() method is typically overridden (or implemented, if inheriting from the interface in the derived class) and returns an object that becomes the value of the target property for this markup extension. In the current example, the ProvideValue() method returns an object used as the source for the XML binding.

The general syntax of the ProvideValue() method is as follows:

Syntax:

public abstract Object ProvideValue(
IServiceProvider serviceProvider
)

Note In the preceding example, serviceProvider indicates a service provider helper that can provide services for the markup extension.

If the service is designed to return a value, the custom markup extension class can throw an exception if the service is unavailable. In addition, if any of the arguments used by the custom markup extension class to provide values are null, or if an argument does not match the expected data type, or if it contains a value that cannot be processed by the custom markup extension, you can throw an exception within the custom markup class. The recommended exception to throw in either or both of these cases is InvalidOperationException.

The following XAML markup assigns the CLR namespace XMLBinderDemo to the alias local. Then it invokes the custom markup extension using this alias and passes the XML file name and path to bind to using the Source and Path attributes as shown here:

<ListBox ItemsSource="{local:XMLBinderExtension Source=Employee.xml,
Path=/Manager/FirstName}" Height="200" Width="200" Background="Beige" />

This approach makes declarative XML binding possible and much easier to work with.

Note The MarkupExtension type is defined in the System.Windows.Markup namespace and not in the System.Xaml namespace. This does not mean that this type is specific to either the WPF or Windows Forms technologies. MarkupExtension is in the System.Xaml assembly and therefore has no specific framework dependency. This type existed in the CLR namespace for .NET Framework 3.0 and remains in the CLR namespace in .NET Framework 4 to avoid breaking references in existing WPF projects.

6) Type Converters versus Markup Extensions

Type converters and markup extensions are similar in that they are used by XAML type systems and XAML writers to render object graph components.

Type converters are classes that derive from the TypeConverter class in the.NET Framework. The TypeConverter class converts a text representation of an object (such as an attribute value or a XAML value node) into an object. You can also use a TypeConverter to serialize an object value to a text representation. The TypeConverter class was present in the.NET Framework long before the development of XAML. Markup extensions, on the other hand, are classes that derive from the MarkupExtension class. Markup extensions are a concept that originated with XAML.

Although type converters and markup extensions have a few characteristics in common, each is represented differently within a XAML node stream. Also, markup extensions return objects in a more elegant manner than type converters. When a type or member includes a type converter implementation, the XAML object writer invokes the type converter.

Type converters are typically associated with types or members, and are invoked when an object graph creation or a serialization method encounters the text representation associated with those entities. Thus, a type converter call is dependent on the type or property definition.

A markup extension is under the control of user code and user-generated markup, and can be called when an application scenario demands it, whereas a type converter is not.

7) XAML Services

The .NET Framework XAML Services are a set of services and APIs defined in the assembly System.Xaml. This is a new assembly introduced with .NET Framework 4, and includes readers, writers, schema classes and other XAML language features.

The System.Xaml assembly also defines types that relate to XAML readers and XAML writers, types for the XAML type system, and other support types related to XAML and .NET Framework XAML Services concepts.

A crucial feature added to XAML Services that was not present in earlier versions of .NET Framework is a type system for XAML.

You can extend the XAML type system functionality of XAML representations into specific features enabled by a framework, an application, and so on that accept and render XAML. The XAML type system provides the APIs required to work with the nodes of a XAML node stream.

8) Security in XAML

Just as with any other .NET technology, XAML addresses security issues to help ensure that your hard work does not go down the drain because of security loopholes.

Any XAML source that your application did not specifically create or render is categorized as untrusted XAML. However, XAML compiled into or stored as a resx-type resource within a trusted and signed assembly can be trusted based on the trust level of the assembly. You should typically treat untrusted XAML as if it were untrusted code.

Through XAML, you work with objects, type converters, assemblies in the application domain, and so on. XAML is also popular for rendering UIs in technologies such as WPF and Silverlight. To secure Silverlight-based applications against attacks, Microsoft recommends that you do not pass untrusted XAML strings to the Load or CreateFromXaml methods.

In addition, you should avoid sharing XAML reader instances, settings for XAML reader/writer classes, or similar such details between trusted and untrusted code.

You must also take care to secure XAML namespace mappings—an untrusted assembly can spoof a trusted assembly's proposed XAML namespace mapping. After the untrusted assembly obtains the XAML namespace mapping, it can grab the object and property information from object sources. Some security measures you can take include using fully qualified assembly names with strong names in XAML namespace mappings, and restricting assembly mapping to a fixed set of reference assemblies.

9) Summary

· The extensions described in this chapter, also called markup extensions, are placeholders to resolve a property at run time.

· The System.Windows.Markup namespace contains the definitions for most of the markup extension classes.

· x:Null, x:Array, x:Reference, x:Static, and x:Type are some of the built-in XAML markup extensions.

· Binding, StaticResource, and DynamicResource are some other commonly used markup extensions that form part of the XAML language. See Chapter 8 for more information.

· Custom markup extensions are useful in scenarios where you need the extension to provide functionality or behavior that is beyond the scope of existing built-in markup extensions.

· The .NET Framework XAML Services are a set of services and APIs defined in the assembly System.Xaml.