Freigeben über


Markup Extensions and XAML

This topic introduces the concept of markup extensions for Extensible Application Markup Language (XAML), including their syntactical rules, purpose, and the class object model that underlies them.

This topic contains the following sections.

  • XAML Readers and Markup Extensions
  • Basic Markup Extension Syntax
  • WPF-Specific Markup Extensions
  • XAML-Defined Markup Extensions
  • More About Markup Extension Syntax
  • Related Topics

XAML Readers and Markup Extensions

A XAML reader is defined as any program that can accept XAML as a language per its specifications (either by compiling, or by interpreting), and produce the resultant underlying classes also per the XAML specifications. By default, such a reader will interpret any attribute value based on the logic of treating as a literal string, or type-converting into an object either on basis of the type of the attribute or the type converters specific to that attribute. However, there are occasional needs to escape from these behaviors when the value of an attribute should instead be a reference to something else, such as an already defined object, or a syntax that allows you to provide non-default arguments to the constructor of any such object that a XAML reader must produce.

Basic Markup Extension Syntax

A markup extension can be implemented to provide values for properties in attribute syntax, properties in property element syntax, or both.

When used to provide an attribute value ,the syntax that distinguishes a markup extension to a XAML reader is the presence of the opening and closing curly braces ({ and }). The type of markup extension is then identified by the string token immediately following the opening curly brace.

When used in property element syntax, a markup extension is visually the same as any other element used to provide a property element value: a XAML element declaration that references the markup extension class as an element, enclosed within angle brackets (<>).

WPF-Specific Markup Extensions

The most common markup extensions used in WPF programming are those that support resource references (StaticResource and DynamicResource), and those that support data binding (Binding).

StaticResource

Provides a value for a XAML property by substituting the value of an already defined resource. For details, see StaticResource Markup Extension.

DynamicResource

Provides a value for a XAML property by deferring that value to be a runtime reference to a resource. A dynamic resource reference forces a new lookup each time that such a resource is accessed. For details, see DynamicResource Markup Extension.

Binding

Provides a data bound value for a property, per the data context that applies to the element. For details, see Binding Markup Extension.

RelativeSource

Gives source information for a Binding that can navigate several possible axes in the runtime element tree. This provides specialized sourcing for bindings that are created in multi-use templates or created in code without full knowledge of the surrounding element tree. For details, see RelativeSource MarkupExtension.

TemplateBinding

Enables a control template to use values for templated properties that come from object-model-defined properties of the class that will use the template. For details, see TemplateBinding Markup Extension. For more information on the practical use of TemplateBinding, see Control Template Examples.

XAML-Defined Markup Extensions

Several markup extensions exist that are not specific to WPF application of XAML, but are instead part of the specified namespace of XAML as a language. These are identifiable by the x: prefix in the syntax. The WPF implementation for these uses the same MarkupExtension base class to provide the implementation.

NoteNote:

The x: prefix is used for the typical namespace mapping of the XAML namespace, in the root element of a XAML application or document. For instance, the Microsoft Visual Studio 2005 templates initiate a XAML file using this x: mapping. You could choose a different prefix token in your own xmlns mapping, but this documentation will assume the default x: mapping as a means of identifying those entities that are a defined part of the XAML namespace, as opposed to the WPF namespace or other arbitrary namespaces.

x:Type

Supplies the Type object for the named type. This is used most frequently in styles and templates. For details, see x:Type Markup Extension.

x:Static

Produces static values from value-type code entities that are not directly the type of a property's value, but can be evaluated to that type. For details, see x:Static Markup Extension.

x:Null

Specifies null as a value for a XAML property. For details, see x:Null Markup Extension .

x:Array

Provides support for creation of general arrays in XAML syntax. For details, see x:Array Markup Extension.

More About Markup Extension Syntax

*Extension Classes

The behavior of each markup extension is identified to a XAML reader through a *Extension class that derives from MarkupExtension, and provides an implementation of the ProvideValue method. This method on each extension defines what object is returned once the markup extension is evaluated. The returned object is typically instantiated or set by using the various string tokens passed to the markup extension.

For example, the StaticResourceExtension class provides the surface implementation of actual resource lookup so that its ProvideValue implementation returns the object that is requested, with the input of that particular implementation being a string that is used to look up the resource by its x:Key. Much of this implementation detail is unimportant if you are using an existing markup extension.

Extension Class Interpretation of Following String Tokens

The string tokens following the markup extension identifier and still within the braces are interpreted by a XAML reader in one of the following ways:

  • A comma always represents the separator or delimiter of individual tokens. Therefore a literal comma cannot be passed to a markup extension.

  • If the individual separated tokens do not contain any equals signs, each token is treated as a constructor argument. Each constructor parameter must be given as the type expected by that signature, and in the proper order expected by that signature.

    NoteNote:

    A XAML reader must call the constructor that matches the argument count of the number of pairs. For this reason, if you are implementing a custom markup extension, do not provide multiple parameters with the same argument count; the behavior for what happens if more than one markup extension constructor with the same parameter count exists is not defined.

  • If the individual separated tokens contain equals signs, then a XAML reader first calls the default constructor for the markup extension. Then, each name=value pair is interpreted as a property name that exists on the markup extension, and a value to assign to that property.

  • If there is parallelism between the constructor behavior and the property setting behavior in a markup extension, it does not matter which behavior you use. It is more common usage to use the property=value pairs for markup extensions that have more than one settable property, if only because it makes your markup more intentional and you are less likely to accidentally transpose constructor parameters (when you specify property=value pairs, those properties may be in any order). Also, there is no guarantee that a markup extension supplies a constructor parameter that sets every one of its settable properties. For instance, Binding is a markup extension, with many properties that are settable through the extension in property=value form, but Binding only supports two constructors: a default, and one that sets an initial path.

Escaping Literal Curly Braces

Attribute handling in a XAML reader uses the curly braces as indicators of a markup extension. It is also possible to produce a literal curly brace character attribute value if necessary, by entering an escape sequence using an empty curly brace pair followed by the literal curly brace. See {} Escape Sequence / Markup Extension.

Nesting Extension Syntax

Nesting of multiple markup extensions is allowed, and will be evaluated deepest first, for instance:

<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />

More About Markup Extensions and Property Element Syntax

Earlier, we noted that the syntax for a markup extension as opposed to an ordinary element that can be used in XAML was visually indistinguishable. The practical difference between an ordinary element and a markup extension in this circumstance is that the markup extension is either evaluated to a typed value or deferred as an expression, and therefore the mechanisms for any possible type errors of property values will be different, similar to how a late-bound property is treated in other programming paradigms. An ordinary element will be evaluated for type versus the property it is setting immediately on compilation.

Most markup extensions, when used in object element syntax to fill a property element, would not have content or any further property element syntax within, and thus you would close the element tag with a forward slash, and provide no child elements. Whenever any object element is encountered by a XAML reader, the constructor for that class is called to instantiate the object created from the parsed element. A markup extension class is no different; therefore, if you want your markup extension to be usable in object element syntax, you must provide a default constructor. Some existing markup extensions have at least one required property value that must be specified for effective initialization, and if so, that property value is typically given as a property attribute on the object element. In the XAML Namespace (x:) Language Features and WPF Namespace XAML Extensions reference pages, markup extensions that have required properties (and the names of required properties) will be noted. Reference pages will also note if either object element syntax or attribute syntax is disallowed for particular markup extensions. A notable case is x:Array Markup Extension, which cannot support attribute syntax because the contents of that array must be specified. The array contents are handled as general objects, therefore no default type converter for the attribute is feasible. Also, x:Array Markup Extension requires a Type parameter.

See Also

Reference

StaticResource Markup Extension
Binding Markup Extension
DynamicResource Markup Extension
x:Type Markup Extension

Concepts

XAML Overview

Other Resources

XAML Namespace (x:) Language Features
WPF Namespace XAML Extensions