A markup extension is a value that is computed when the markup is read instead of being converted from text: a reference to a resource, a data binding, a static member, a type. In an attribute it is written in curly braces. It stands for an object of a class that derives from MarkupExtension and has a method ProvideValue; the name in the braces is the class name with or without the suffix Extension ({Binding} is BindingExtension’s relative, {x:Static} is StaticExtension). The class is also usable as an object element (<StaticResource ResourceKey="a"/>) where the framework allows it.
The grammar
Extension ::= '{' S? Name ( S Arguments )? S? '}'
Name ::= ( Prefix ':' )? TypeName
Arguments ::= Argument ( S? ',' S? Argument )*
Argument ::= ( Key S? '=' S? )? Value
Value ::= Quoted | Extension | Escaped | Bare
Quoted ::= "'" … "'" | '"' … '"' (a backslash makes the next character plain)
Escaped ::= '{}' Bare (the text after {} is plain, braces in balance)
Bare ::= any text up to the next ',' or the closing '}', braces in balance
- Where it starts. An attribute value is a markup extension when its first character is
{and the second is not}. The same holds for the text of a property element. A{anywhere else is plain text. White space before the{makes the value plain text. - Positional arguments are values with no
Key=, given in order to a constructor of the extension class:{StaticResource Brand},{Binding Name}. They come first; a positional argument after a named one is an error. - Named arguments are
Key=Valuepairs that set properties of the extension, in any order:{Binding Path=Name, Mode=TwoWay}. A name may be an attached property in parentheses:Path=(Grid.Row). - Commas and quotes. A comma separates arguments. A value that contains a comma, a brace or leading or trailing spaces is written in single or double quotes:
StringFormat='{}{0:N2}, units'. Inside a quoted value a backslash makes the next character plain (\',\\,\,). Only white space may follow the closing quote. - Nesting. A value may be another extension; the innermost is evaluated first:
{DynamicResource {x:Static SystemColors.ControlBrushKey}},{Binding Path=Name, Converter={StaticResource Upper}}. - The
{}escape. A value that starts with{}is plain text:Text="{}{0}"is the text{0}. Inside an extension, a value that must start with a brace needs it too:StringFormat={}{0:C}. A double quote cannot be escaped this way; use"or a single quote around the attribute’s own value. - Empty extension.
{Binding}is a binding to the data context itself;{}alone is the escape with nothing after it. - Errors. an unclosed brace, an unclosed quote, characters after a closing quote or after the closing brace, an empty argument, a missing name: the reader refuses the file. The viewer reports each of these and shows what it could read.
Markup extensions work in attributes and in the text of property elements. In the content of an object element (text directly inside a TextBlock), the braces are plain text.
Language extensions (the x: namespace)
| Extension | Arguments | Result |
|---|---|---|
{x:Null} | none | null |
{x:Type Name} | one: a type name with a prefix if needed | the System.Type |
{x:Static Type.Member} | one: Type.Member | the static field, property, constant or enumeration value |
{x:Reference name} | one: an x:Name | the named object (WPF 4, MAUI, Xamarin.Forms, Avalonia) |
{x:Array} | element form only in WPF | an array |
{x:Bind Path, …} | see below | a compiled binding (UWP, WinUI) |
WPF
| Extension | Arguments | Meaning |
|---|---|---|
{StaticResource Key} | ResourceKey (positional, required) | looks the key up once, while the markup is loaded; the resource must be defined earlier in the file or in an enclosing scope; a missing key is an error at load |
{DynamicResource Key} | ResourceKey | looks the key up each time the value is needed and again if the resource changes; only for dependency properties; may refer to a resource defined later |
{Binding …} | positional: Path; named: AsyncState, BindingGroupName, BindsDirectlyToSource, Converter, ConverterCulture, ConverterParameter, Delay, ElementName, FallbackValue, IsAsync, Mode, NotifyOnSourceUpdated, NotifyOnTargetUpdated, NotifyOnValidationError, Path, RelativeSource, Source, StringFormat, TargetNullValue, UpdateSourceExceptionFilter, UpdateSourceTrigger, ValidatesOnDataErrors, ValidatesOnExceptions, ValidatesOnNotifyDataErrors, ValidationRules, XPath | see data binding |
{RelativeSource Mode} | positional: Mode; named: Mode (Self, TemplatedParent, FindAncestor, PreviousData), AncestorType, AncestorLevel | the source of a binding by its place in the tree |
{TemplateBinding Property} | Property (a dependency property of the templated type) | a one-way, light binding to a property of the control a template is applied to |
{ThemeDictionary AssemblyName} | AssemblyName | the theme dictionary of an assembly, as a ResourceDictionary.Source |
{ComponentResourceKey …} | named: TypeInTargetAssembly, ResourceId | a resource key made of a type and an id, so that a custom control’s resources do not clash |
{ColorConvertedBitmap …} | Image, SourceColorContext, DestinationColorContext, RenderIntent | an image with a colour profile applied |
{PropertyPath …} | Path, PathParameters | a property path |
UWP and WinUI
| Extension | Arguments | Meaning |
|---|---|---|
{Binding …} | positional: Path; named: Converter, ConverterLanguage, ConverterParameter, ElementName, FallbackValue, Mode, Path, RelativeSource, Source, TargetNullValue, UpdateSourceTrigger | a run-time binding (reflection) |
{x:Bind …} | positional: Path; named: BindBack, Converter, ConverterLanguage, ConverterParameter, Delay, FallbackValue, Mode (OneTime is the default, OneWay, TwoWay), Path, TargetNullValue, UpdateSourceTrigger | a binding compiled into code; the path starts at the page or user control, not at the data context; also binds to methods and events |
{StaticResource Key} | ResourceKey | as in WPF |
{ThemeResource Key} | ResourceKey | like a static lookup that is made again when the theme changes (light, dark, high contrast) |
{TemplateBinding Property} | a property | as in WPF |
{RelativeSource Self}, {RelativeSource TemplatedParent} | Mode | the only two relative sources |
{CustomResource Key} | ResourceKey | a custom resource lookup defined by a CustomXamlResourceLoader |
.NET MAUI and Xamarin.Forms
| Extension | Arguments | Meaning |
|---|---|---|
{Binding …} | positional: Path; named: Converter, ConverterParameter, FallbackValue, Mode, Path, Source, StringFormat, TargetNullValue, UpdateSourceEventName | a binding; . is the binding context; with x:DataType a compiled binding |
{StaticResource Key}, {DynamicResource Key} | the key | as in WPF |
{TemplateBinding Path}, {RelativeSource …} | a path; Mode, AncestorType, AncestorLevel | bindings to the templated parent and to relative sources |
{x:Reference name}, {x:Static …}, {x:Type …}, {x:Null} | as above | as above |
{OnPlatform …}, {OnIdiom …} | named: Default, platform or idiom names (Android, iOS, WinUI, Phone, Tablet, Desktop …) | a value that depends on the platform or the device |
{AppThemeBinding …} | named: Light, Dark, Default | a value for the light and dark theme (MAUI) |
{FontImage …} | named: Glyph, FontFamily, Color, Size | an image from a font glyph |
Avalonia
| Extension | Meaning |
|---|---|
{Binding …}, {CompiledBinding …}, {ReflectionBinding …} | bindings; {Binding} is compiled when x:CompileBindings="True" (default in newer templates) and uses reflection otherwise; paths can use #name.Property for a named element, $parent[Type].Property for an ancestor, $self.Property, ^ for observables and tasks |
{StaticResource …}, {DynamicResource …}, {TemplateBinding …} | as in WPF |
{x:Static …}, {x:Null}, {x:Type …}, {x:Reference …} | as above |
{OnPlatform …}, {OnFormFactor …} | a value that depends on the operating system or the form factor |
Your own
Any class that derives from MarkupExtension (WPF, System.Xaml), IMarkupExtension (MAUI) or the framework’s own base is a markup extension: {local:Translate Key=Save}. Its name in markup is the class name, and its positional arguments call the constructor with that many parameters. The viewer shows an extension it does not know with the note “not a markup extension this viewer knows”: that is a fact about the viewer, not a fault of the file.
Not described
Known, not yet covered
- Reference: the argument lists of MAUI’s
OnPlatformand Avalonia’s binding path operators are summarised, not complete. - Reference: the extensions of third-party libraries (Prism, MahApps, Material Design, community toolkits) are not listed.
- Viewer: arity and unknown-property checks are made for the extensions marked as known in the tables only for the WPF and UWP/WinUI forms of
Binding,x:BindandRelativeSource; for other frameworks the arguments are parsed and shown, not checked. - Viewer: a markup extension inside the content of an object element is not looked for, because the frameworks treat that text as plain.
Unknown
- Reference: how every framework treats white space before the opening brace of a value was not tested; the page states the rule of the XAML services documentation.