Learn the rules of XAML: how elements become objects, attributes become properties, when to use property element syntax, content properties, collections and type converters.

Bishal Biswas
Self Learner
What XAML really is
XAML stands for eXtensible Application Markup Language. It looks like HTML, but there is one big idea to hold on to:
Every XAML element creates a C# object, and every attribute sets a property on that object.
That is it. XAML is just a short, readable way to create objects and set their properties. Anything you write in XAML, you could also write in C#. Look at this button:
<Button Content="Save" Width="100" />
It does the same as this C#:
var button = new Button();
button.Content = "Save";
button.Width = 100;
Once you see XAML this way, the rules below make a lot of sense.
XAML is XML
XAML follows the rules of XML, a general format for structured text. That means:
- Every element has a start tag and an end tag:
<StackPanel>…</StackPanel>. - An element with nothing inside can close itself:
<Button />. - Attribute values always go in quotes:
Width="100", neverWidth=100. - Elements must be properly nested. You cannot close an outer element before an inner one.
- There is exactly one root element (the outermost one), such as
Window.
<!-- Good: properly nested -->
<StackPanel>
<TextBlock Text="One" />
<TextBlock Text="Two" />
</StackPanel>
<!-- Bad: the TextBlock is closed after the StackPanel -->
<StackPanel>
<TextBlock Text="One">
</StackPanel>
</TextBlock>
Case matters
XAML is case sensitive. Button works, button does not. Width works, width does not. Names match the C# class and property names exactly.
Comments
Comments use the XML style. They can span several lines:
<!-- This is a comment. WPF ignores it. -->
<Button Content="OK" />
You cannot put a comment inside a tag, only between elements.
Elements are objects
Each element name is the name of a class. TextBlock creates a System.Windows.Controls.TextBlock object, Border creates a Border, and so on. When elements are nested, the inner ones become children of the outer one:
<Border BorderBrush="Gray" BorderThickness="1" Padding="10">
<TextBlock Text="Inside a border" />
</Border>
In C# that would be:
var border = new Border
{
BorderBrush = Brushes.Gray,
BorderThickness = new Thickness(1),
Padding = new Thickness(10),
Child = new TextBlock { Text = "Inside a border" }
};
Notice how much shorter and easier to read the XAML version is. That is why we describe screens in XAML.
Attributes are properties
An attribute sets a property. The value is always written as text, and WPF turns that text into the right type. This is called attribute syntax:
<TextBlock Text="Total spent"
FontSize="18"
FontWeight="Bold"
Foreground="DarkSlateBlue"
Margin="0,0,0,10" />
Attributes can also hook up events, like Click="Save_Click". You will look at those in Code-Behind and Event Handlers.
Type converters: text into objects
How does "0,0,0,10" become a margin, or "DarkSlateBlue" become a colour? WPF uses type converters: small helpers that turn a string into the type a property needs. You never call them yourself, they run automatically.
Here are the conversions you will use most:
Width="120" a double: 120
IsEnabled="False" a bool: false
FontWeight="Bold" an enum value: FontWeights.Bold
Foreground="Red" a named colour brush
Background="#FF2E7D32" a colour in hex: alpha, red, green, blue
Background="#2E7D32" hex without alpha (fully opaque)
Margin="10" 10 on all four sides
Margin="10,5" 10 left and right, 5 top and bottom
Margin="10,5,10,0" left, top, right, bottom
HorizontalAlignment="Right" an enum value
Margins go left, top, right, bottom, clockwise starting from the left. You will use them a lot in Layout Basics: Size, Margin and Alignment.
Property element syntax
Sometimes a property value is too complex to fit in a string. For example, a background that fades from one colour to another. For that, XAML has property element syntax: you write the property as its own element, named TypeName.PropertyName:
<Button Content="Gradient button" Height="40">
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="LightSkyBlue" Offset="0" />
<GradientStop Color="SteelBlue" Offset="1" />
</LinearGradientBrush>
</Button.Background>
</Button>
Button.Background is not a new control. It means “set the Background property of this Button to the object inside”. Both forms below do exactly the same thing:
<!-- Attribute syntax -->
<Button Background="LightGreen" Content="OK" />
<!-- Property element syntax -->
<Button Content="OK">
<Button.Background>
<SolidColorBrush Color="LightGreen" />
</Button.Background>
</Button>
Use the short attribute form when a string is enough, and the property element form when it is not. You already saw property element syntax in App.xaml: Application.Resources is one.
The content property
Many controls have one special property, the content property, that you can set by simply putting something between the start and end tags. For a Button it is Content. For a TextBlock, text between the tags becomes the text it shows. For a Border it is Child.
<!-- These three buttons are the same -->
<Button Content="Save" />
<Button>Save</Button>
<Button>
<Button.Content>Save</Button.Content>
</Button>
The content of a Button does not have to be text. It can be any object, even a whole layout:
<Button Padding="10,5">
<StackPanel Orientation="Horizontal">
<TextBlock Text="💰" Margin="0,0,6,0" />
<TextBlock Text="Add coin" />
</StackPanel>
</Button>
This is one of WPF’s superpowers: almost anything can go inside almost anything. 💰 is the code for a money bag emoji. Writing characters as &#x...; codes works anywhere in XAML.
One child or many
Some elements take one child and some take many:
Window,Button,Bordertake one child. To put several things in a window, you wrap them in a panel.- Panels like
StackPanelandGridtake many children. Their content property isChildren, a collection.
<!-- Error: a Window can only have one child -->
<Window ...>
<TextBlock Text="One" />
<TextBlock Text="Two" />
</Window>
<!-- Fix: wrap them in a panel -->
<Window ...>
<StackPanel>
<TextBlock Text="One" />
<TextBlock Text="Two" />
</StackPanel>
</Window>
Collections
When a property is a list, you add items by just listing them inside. A ComboBox is a good example:
<ComboBox Width="150" SelectedIndex="0">
<ComboBoxItem Content="Food" />
<ComboBoxItem Content="Transport" />
<ComboBoxItem Content="Bills" />
<ComboBoxItem Content="Fun" />
<ComboBoxItem Content="Other" />
</ComboBox>
WPF adds each ComboBoxItem to the Items collection. These are the CoinJar categories, and later you will fill this list from data instead of typing items by hand, in Binding to Collections with ObservableCollection.
Special characters
Because XAML is XML, a few characters have special meaning and must be written as entities (codes) inside attribute values and text:
< write <
> write >
& write &
" write " (or use single quotes around the value)
For example:
<TextBlock Text="Food & Drink" />
<TextBlock Text="Amount < 100" />
<TextBlock Text='Say "hi"' />
Naming elements with x:Name
Give an element a name with x:Name so C# code can use it:
<TextBox x:Name="TitleBox" />
In the code-behind, TitleBox is now a field you can read and change. Names must be unique in a window and follow C# naming rules (no spaces, cannot start with a number). The x: prefix comes from a namespace you will understand in XAML Namespaces and Markup Extensions.
Common mistakes
- Wrong case.
<textblock>orfontsize="12"fail. Match the C# names exactly. - Missing quotes.
Width=100is not valid XML. - Two children in a one child element. You get “The property Content is set more than once”. Wrap them in a panel.
- Setting the same property twice. For example
Content="OK"and also text between the tags. Pick one. - A raw
&in text. Write&instead.
Tips
- Indent nested elements by four spaces. It makes the tree shape easy to see.
- Put each attribute on its own line when a tag gets long.
- When you are not sure how to write something in XAML, think “what would the C# look like?” and translate.
Quick recap
- Each XAML element creates an object, and each attribute sets a property.
- XAML follows XML rules: quoted values, properly nested tags, one root, case sensitive.
- Type converters turn text like
"10,5"or"#2E7D32"into the right types. - Property element syntax (
Button.Background) sets a property to a complex object. - The content property lets you put a value between the tags, and a
Buttoncan hold any content. - One child elements need a panel to hold several controls, and collections are filled by listing items.
- Write
<,>and&for special characters.
<!-- MainWindow.xaml -->
<!-- A XAML playground. Try changing values and running the app. -->
<Window x:Class="CoinJar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XAML Playground" Width="420" SizeToContent="Height"
WindowStartupLocation="CenterScreen">
<!-- Window has one child, so a StackPanel holds everything -->
<StackPanel Margin="20">
<!-- Attribute syntax: plain text values, turned into the right types -->
<TextBlock Text="New expense" FontSize="20" FontWeight="Bold"
Foreground="#2E7D32" Margin="0,0,0,10" />
<!-- Special characters: & becomes & on screen -->
<TextBlock Text="Title (for example: Food & Drink)" />
<TextBox x:Name="TitleBox" Margin="0,4,0,10" />
<TextBlock Text="Category" />
<!-- Collection syntax: items are listed inside -->
<ComboBox x:Name="CategoryBox" SelectedIndex="0" Margin="0,4,0,10">
<ComboBoxItem Content="Food" />
<ComboBoxItem Content="Transport" />
<ComboBoxItem Content="Bills" />
<ComboBoxItem Content="Fun" />
<ComboBoxItem Content="Other" />
</ComboBox>
<!-- Content property: a whole layout inside a Button -->
<Button HorizontalAlignment="Left" Padding="12,6">
<!-- Property element syntax: a gradient is too complex for one string -->
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#C8E6C9" Offset="0" />
<GradientStop Color="#81C784" Offset="1" />
</LinearGradientBrush>
</Button.Background>
<StackPanel Orientation="Horizontal">
<!-- 💰 is a money bag emoji -->
<TextBlock Text="💰" Margin="0,0,6,0" />
<TextBlock Text="Add coin" FontWeight="SemiBold" />
</StackPanel>
</Button>
<!-- Border takes one child -->
<Border BorderBrush="Gray" BorderThickness="1" CornerRadius="4"
Padding="10" Margin="0,16,0,0">
<TextBlock TextWrapping="Wrap">
Text between the tags works too: a TextBlock shows it as its text.
</TextBlock>
</Border>
</StackPanel>
</Window>
Was this explanation helpful?
Your feedback helps us improve the content for everyone.
Thank you for your feedback!
We appreciate you helping us improve.
What could we improve? (Optional)
Read aloud
Ready