XAML

Windows Presentation Foundation builds upon Extensible Application Markup Language (XAML), an extension of the XML language we’ve discussed previously. Just like XML, it consists of elements defined by opening and closing tags.

For example, a button is represented by:

<Button></Button>

Which, because it has no children, could also be expressed with a self-closing tag:

<Button/>

In addition, elements can have attributes, i.e we could add a height, width, and content to our button:

<Button Height="30" Width="120" Content="Click Me!"/>

XAML also offers an expanded property syntax that is an alternative to attributes. For example, we could re-write the above button as:

<Button>
  <Button.Height>30</Button.Height>
  <Button.Width>120</Button.Width>
  <Button.Content>Click Me!</Button.Content>
</Button>

Note how we repeat the tag name (Button) and append the attribute name (Height, Width, and Content to it with a period between the two). This differentiates the expanded property from nested elements, i.e. in this XAML code:

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="200"/>
    <ColumnDefinition Width="200"/>
    <ColumnDefinition Width="200"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition/>
    <RowDefinition/>
  </Grid.RowDefinitions>
  <Button Height="30" Width="120" Content="Click Me!"/>
</Grid>

<Grid.ColumnDefinitions> and <Grid.RowDefinitions> are attributes of the <Grid>, while <Button Height="30" Width="120" Content="Click Me!"/> is a child element of the <Grid> element.

Because XAML is an extension of XML, we can add comments the same way, by enclosing the comment within a <!-- and -->:

<!-- I am a comment -->

XAML Defines Objects

What makes XAML different from vanilla XML is that it defines objects. The XAML used for Windows Presentation Foundation is drawn from the

namespace. This namespace defines exactly what elements exist in this flavor of XAML, and they correspond to specific classes defined in the WPF namespaces.

For example, the <Button> class corresponds to the WPF Button class. This class has a Content property which defines the text or other content displayed on the button. Additionally, it has a Width and Height property. Thus the XAML:

<Button Height="30" Width="120" Content="Click Me!"/>

Effectively says construct an instance of the Button class with its Height property set to 30, its Width property set to 120, and its Content property set to the string "Click Me!". Were we to write the corresponding C# code, it would look like:

var button = new Button();
button.Height = 30;
button.Width = 120;
button.Content = "Click Me!";

This is why XAML stands for Extensible Application Markup Language - it’s effectively another way of writing programs! You can find the documentation for all the controls declared in the xaml/presentation namespace on docs.microsoft.com.

XAML and Partial Classes

In addition to being used to define objects, XAML can also be used to define part of a class. Consider this MainWindow XAML code, which is generated by the Visual Studio WPF Project Template:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
    </Grid>
</Window>

And its corresponding C# file:

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

Notice the use of the partial modifier in the C# code? This indicates that the MainWindow class is only partially defined in this file (MainWindow.xaml.cs) - the rest of the definition exists in another file. That’s the previously referenced XAML file (MainWindow.xaml). Notice in the XAML that the <Window> element has the attribute x:Class="WpfApp1.MainWindow"? That indicates that it defines part of the class MainWindow defined in the WpfApp1 namespace - it’s the other part of our file!

When we compile this project, the XAML is actually transformed into a temporary C# file as part of the build process, and that C# file is joined with the other C# file. This temporary file defines the InitializeComponent() method, which would look something like this:

void InitializeComponent() 
{
    this.Title = "MainWindow";
    this.Height = 450;
    this.Width = 800;

    var grid = new Grid();
    this.Content = grid;
}

Notice how it sets the properties corresponding to the attributes defined on the <MainWindow> element? Further, it assigns the child of that element (a <Grid> element) as the Content property of the Window. Nested XAML elements are typically assigned to either Content or Children properties, depending on if the element in question is a container element or not (container elements can have multiple children, all other elements are limited to a single child).

Any structure defined in our XAML is set up during this InitializeComponent() call. This means you should never remove the InitializeComponent(); invocation from a WPF class, or your XAML-defined content will not be added. Similarly, you should not manipulate that structure until the InitializeComponent(); method has been invoked, or the structure will not exist!

This strategy of splitting GUI code into two files is known in Microsoft parlance as codebehind, and it allows the GUI’s visual aspect to be created independently of the code that provides its logic. This approach has been a staple of both Windows Forms and Windows Presentation Foundation. This separation also allows for graphic designers to create the GUI look-and-feel without ever needing to write a line of code. There is a companion application to Visual Studio called Blend that can be used to write the XAML files for a project without needing the full weight and useability of Visual Studio.

Tip

Occasionally, Visual Studio will encounter a problem while building the temporary file from the XAML definition, and the resulting temporary file may become corrupted. When this happens, your changes to the XAML are no longer incorporated into the program when you compile, because the process can’t overwrite the corrupted temporary file. Instead, the corrupted temporary file is used - resulting in weird and unexpected behavior. If this happens to you, just run the “Build > Clean” menu option on the project to delete all the temporary files.

Info

Partial classes weren’t a WPF-specific innovation - Windows Forms used them first. In Windows Forms, when you create a form, Visual Studio actually creates two C# files. One of these is the one intended for you to edit, and the other is used by the drag-and-drop editor, which fills it with auto-generated C# code. If you ever make the mistake of editing this file, it will cause all kinds of problems for the drag-and-drop editor (and you)! In contrast, the drag-and-drop editor for WPF actually modifies the same XAML file you do - allowing you to use the editor, manually edit the XAML, or any combination of the two.