Home > Articles > Programming > C#

Mastering XAML

  • Print
  • + Share This
This chapter is from the book

Markup Extensions

Markup extensions, like type converters, extend the expressiveness of XAML. Both can evaluate a string attribute value at runtime and produce an appropriate object based on the string. As with type converters, you cannot currently create your own, but several markup extensions are built in.

Unlike type converters, markup extensions are invoked from XAML with explicit and consistent syntax. Whenever an attribute value is enclosed in curly braces ({}), the XAML parser treats it as a markup extension value rather than a literal string or something that needs to be type-converted. The following Button uses two different markup extensions as the values for two different properties:

The first identifier in each set of curly braces is the name of the markup extension. The Null extension lives in the XAML language namespace, so the x prefix must be used. Binding (which also happens to be a class in the Windows.UI.Xaml.Data namespace), can be found in the default XML namespace. Note that the full name for Null is NullExtension, and this long form can be used as well in XAML. XAML permits dropping the Extension suffix on any markup extensions named with the suffix.

If a markup extension supports them, comma-delimited parameters can be specified. Positional parameters (such as Height in the example) are treated as string arguments for the extension class’s appropriate constructor. Named parameters (RelativeSource in the example) enable you to set properties with matching names on the constructed extension object. The values for these properties can be markup extension values themselves (using nested curly braces, as done with the value for RelativeSource) or literal values that can undergo the normal type conversion process. If you’re familiar with .NET custom attributes (the .NET Framework’s popular extensibility mechanism), you’ve probably noticed that the design and usage of markup extensions closely mirrors the design and usage of custom attributes. That is intentional.

In the preceding Button declaration, x:Null enables the Background brush to be set to null. This is just done for demonstration purposes, because a null Background is not very useful. Binding, covered in depth in Chapter 17, “Data Binding,” enables Content to be set to the same value as the Height property.

Markup extensions can also be used with property element syntax. The following Button is identical to the preceding one:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Button.Height>
    50
  </Button.Height>
  <Button.Background>
    <x:Null/>
  </Button.Background>
  <Button.Content>
    <Binding Path="Height">
      <Binding.RelativeSource>
        <RelativeSource Mode="Self"/>
      </Binding.RelativeSource>
    </Binding>
  </Button.Content>
</Button>

This transformation works because these markup extensions all have properties corresponding to their parameterized constructor arguments (the positional parameters used with property attribute syntax). For example, Binding has a Path property that has the same meaning as the argument that was previously passed to its parameterized constructor, and RelativeSource has a Mode property that corresponds to its constructor argument.

  • + Share This
  • 🔖 Save To Your Account