XAML has three forms of element and attribute, and the rest is conversion. An object element makes an object. An attribute sets a property of it or connects an event. A property element sets a property to an object, a collection or text written in its own element. The reader decides which form it has by the name and by where the element stands.
Object elements
An element whose name is a type (Button, local:Thing, sys:String) makes an instance of that type. The type needs a parameterless constructor, or the XAML 2009 forms x:Arguments (constructor arguments) and x:FactoryMethod (a static method), or it must be a type with a type converter that reads the element’s text. The element may be empty (<Button/>) or hold content. The name before any colon is a namespace prefix; with no colon the name is in the default namespace.
Attribute syntax
An attribute Name="value" on an object element sets the property Name of the object, or, for a name that is an event, connects the event to a method. A value is a string, and the reader converts it to the type of the property:
- If the value starts with
{and the next character is not}, it is a markup extension. - Otherwise, if the property’s type is an enumeration, the value is a name of a member (
HorizontalAlignment="Center") or, for a flags enumeration, names separated by commas (AllowedEffects="Copy, Move"), compared without regard to case. - Otherwise, if the property’s type (or the property itself) has a type converter, the converter reads the string (the table below).
- Otherwise, a primitive type reads it with its own rules:
BooleanisTrueorFalse(any case), numbers use the invariant culture (a period for the decimal point),Stringis the text as it is.
The string is the value after XML has resolved character references and normalised line ends; a leading {} is removed and the rest is plain text (Text="{}{0:N2}" is the text {0:N2}). A quotation mark cannot be escaped with {}; write " or use the other kind of quotation mark for the attribute.
Property element syntax
A child element named Type.Property is a property element: its content is the value of that property of the parent. The type is the type that owns the property, usually the parent’s own type (or a base class of it), written with no space around the dot:
<Button>
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Gold" Offset="0"/>
<GradientStop Color="Orange" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
Go
</Button>
- A property element has no attributes of its own, apart from namespace declarations and
xml:*attributes. XAML 2009 allows anxmlnsdeclaration on it. - A property element is only a child of an object element, and its content is an object element, text, or a markup extension. A property element inside another property element is an error.
- A property can be set once: as an attribute or as a property element, not both, and not by two property elements.
- The root element cannot be a property element.
- The text of a property element is converted like an attribute value, with the white space rules of the file structure page.
Content properties and collections
A type can name one property as its content property (the .NET attribute ContentPropertyAttribute); what is written directly inside the element, with no property element around it, is the value of that property. Button’s is Content, Grid’s and every panel’s is Children, ListBox’s is Items, TextBlock’s is Inlines, Border’s is Child, ResourceDictionary’s is its own items. MAUI and Xamarin.Forms use the same attribute (ContentPage.Content, Layout.Children), and in Avalonia Content and Children work the same way.
When the content property (or any property) is a collection (a list or a dictionary), the child elements are its items and the collection element may be left out. The reader creates the collection if the property has none, or adds to the one it has. With a list (IList or ICollection<T>), each child is an item; with a dictionary (IDictionary), each child needs a key, which is the x:Key attribute or an implied key (see Resources). An explicit form puts the collection element inside the property element: <Grid.RowDefinitions><RowDefinitionCollection>…</RowDefinitionCollection></Grid.RowDefinitions>; it is rarely written.
A content property that holds a single object takes one child; two children are an error (a Button takes one content element, a StackPanel any number). Text mixed with elements is converted to strings in a collection that accepts them (white space).
Type converters: the text formats
Each of these is the text a WPF converter reads for a property of that type. UWP, WinUI, MAUI and Avalonia read the same forms for the types they share, with the differences in the last column.
| Type | Forms | Examples | Others differ |
|---|---|---|---|
Thickness, Margin, Padding | one number for all four sides; two (horizontal, vertical); four (left, top, right, bottom) | 5, 10,4, 1,2,3,4 | UWP and WinUI: the same; MAUI Thickness: one, two or four numbers; Avalonia: the same, and spaces may replace commas |
CornerRadius | one or four numbers (top-left, top-right, bottom-right, bottom-left) | 4, 4,4,0,0 | the same |
Color | #RRGGBB, #AARRGGBB, a name from the known colours, sc#A,R,G,B (scRGB, WPF) | #FF0000, #80FF0000, Red, sc#1,0.5,0.5,0.5 | MAUI Color: also #RGBA, rgb(), rgba(), hsl(), hsla(), names; Avalonia: #RGB, #RGBA, #RRGGBB, #AARRGGBB |
Brush | a colour (makes a SolidColorBrush); otherwise a brush element | Background="Navy" | the same |
Point, Vector, Size | two numbers separated by a comma or a space | 10,20; Size accepts Empty | the same |
Rect | four numbers: x, y, width, height; or Empty | 0,0,100,50 | the same |
Int32Rect | four integers | 0,0,32,32 | not in the others |
GridLength | a number of pixels, Auto, * or a number followed by * (a share of the space left) | 100, Auto, 2* | the same (MAUI: GridLength also Auto, *); Avalonia: the same |
Duration, TimeSpan, KeyTime | [d.]h:mm:ss[.fffffff]; Duration also Automatic and Forever; KeyTime also a percentage and Uniform and Paced | 0:0:2, 00:00:00.5, 50% | the same |
RepeatBehavior | a count followed by x, a duration, or Forever | 3x, 0:0:5, Forever | the same |
FontFamily | a comma separated list of family names or file addresses with a fragment | Segoe UI, Arial, /Fonts/#Lato | MAUI: a registered font alias |
FontWeight, FontStyle, FontStretch | names; FontWeight also a number from 1 to 999 in WPF | Bold, Italic, SemiBold | MAUI: FontAttributes is Bold, Italic or None |
Uri, ImageSource | a relative or absolute address, including pack://application:,,,/Assembly;component/path (WPF) and ms-appx:///path (UWP and WinUI) | Images/logo.png | Avalonia: avares://Assembly/path, /Assets/x.png |
Geometry, PathGeometry, StreamGeometry | the path mini-language: Brushes, shapes, transforms and animation | M 0,0 L 10,10 Z | the same |
Transform | m11,m12,m21,m22,offsetX,offsetY (a matrix), or Identity | 1,0,0,1,10,20 | Avalonia: also a list of CSS-like functions such as rotate(45deg) scale(1.2) |
PointCollection, DoubleCollection | numbers separated by commas or spaces | 0,0 10,10 20,0 | the same |
Cursor | a name, or the address of a .cur or .ani file | Hand | — |
KeyGesture, RoutedCommand | Modifiers+Key with optional display string after a comma | Ctrl+S, Ctrl+Shift+Z | Avalonia: KeyGesture the same |
DateTime | the invariant culture’s date forms | 2009-03-01 | — |
Type, DependencyProperty, RoutedEvent | a type name with an optional prefix; Class.Property for a property or event | local:Person, Button.Click | the same |
Attached properties and attached events
An attached property is defined by one type and set on another: the panel defines Grid.Row and the child carries it. In XAML it is written as an attribute or a property element named Owner.Property on the child (<Button Grid.Row="1"/>; <Button><Grid.Row>1</Grid.Row></Button>). The owner may be a prefixed type: local:Tools.Tag="x". An attached event is written the same way: Button.Click="OnAnyClick" on a parent connects to the clicks of its children (routed events), and Mouse.MouseEnter or Keyboard.KeyDown name an event of another class on any element. A property element whose type name is not the parent’s type (<Grid.Row> in a Button) is therefore an attached property, or a property of a base class; the viewer cannot tell which without the assemblies and does not report it.
Attached property names in a binding path or a trigger are written in parentheses: Path=(Grid.Row), (local:Tools.Tag).
Events
An attribute whose name is an event of the element, with the name of a method as its value, connects the event: Click="OnClick". The method is looked up in the code-behind class (the class named by x:Class) when the markup is compiled, and must have the event’s signature (for a routed event: void OnClick(object sender, RoutedEventArgs e)). A file that is not compiled with a code-behind cannot name handlers: loading it with XamlReader.Load fails on an event attribute. Routed events come in a bubbling form (MouseDown) and a tunnelling form (PreviewMouseDown). In a Style, an EventSetter connects a handler to every element the style applies to: <EventSetter Event="MouseDoubleClick" Handler="OnDouble"/>; an EventTrigger starts an animation on an event: <EventTrigger RoutedEvent="Button.Click">. XAML 2009 allows an event attribute to be wired at load time without compilation. UWP and WinUI can also bind an event to a method of the view model with x:Bind (Click="{x:Bind Vm.Save}"), and MAUI wires commands (Command="{Binding SaveCommand}") more than events.
Property paths
Some properties (Binding.Path, Storyboard.TargetProperty, Setter.TargetName’s property) take a path through objects. The WPF PropertyPath syntax:
| Form | Meaning |
|---|---|
Name | a property of the source |
A.B.C | a property of a property of a property |
Items[2], Dict[key] | an indexer (a number or a string) |
(Grid.Row), (local:Tools.Tag) | an attached or otherwise qualified property, in parentheses |
(Shape.Fill).(SolidColorBrush.Color) | a property of the object a qualified property holds |
/, /Name, Items/Name | the current item of a collection view, and a property of it |
. | the source itself |
RenderTransform.(RotateTransform.Angle) | a path in a storyboard through a transform |
Characters that need care
<and&are written<and&in text and in attribute values;>may be written as it is except in the sequence]]>.- A
{starting an attribute value starts a markup extension; start the value with{}to write a literal brace. - A line break written inside an attribute value is a space (XML normalises it); write
for a line feed, or use a property element. - In a markup extension, a comma separates arguments and a brace ends the extension: quote or escape them (markup extensions).
- A string with leading or trailing spaces is trimmed unless
xml:space="preserve"is used on a property element, or the value is quoted in a way the property allows.
Not described
Known, not yet covered
- Reference: the converter table lists the common types; every type’s converter (for instance every
DependencyPropertyof the 3D classes,Matrix3D,Vector3D,Point3DandInt32Rectforms) is not given. - Reference: the differences of the MAUI, Avalonia and UWP converters are listed where they were found in the documentation, not exhaustively.
Unknown
- Reference: none of the forms was loaded by a real XAML reader here.