Examination of a simple C# based Xaml app

In this blog entry, I will demonstrate a very simple Hello World application using C# and Avalon, and attempt to explain how it works, and how the XAML and the C# code are all hooked up together. All the information and code is based on the February 2006 CTP, and may be subject to change in future (actually Beta 2 was released a day ago).

The Hello World app

Create a new C# WinFX project and choose the WinFX Windows Application template. Visual Studio will generate two XAML files for you, along with corresponding code-behind C# files. You’ll have a MyApp.xaml as follows, which represents the XAML for the Application object.

<Application x:Class="WpfHelloWorld.MyApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml"
    >
    <Application.Resources>
    </Application.Resources>
</Application>

And a corresponding C# source file, MyApp.xaml.cs :

namespace WpfHelloWorld
{
    public partial class MyApp : Application
    {
    }
}

Interestingly, there is no entry point method (usually main for a C# app), and there is also no code that instantiates the Application object. There’s also a Window1.xaml that’s generated for us :

<Window x:Class="WpfHelloWorld.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WpfHelloWorld" Height="300" Width="300"
    >
    <Grid>
    </Grid>
</Window>

And the corresponding Window1.xaml.cs :

namespace WpfHelloWorld
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
    }
}

There is a call made to InitializeComponent but we have not declared such a method in our class nor is there such a method in the Window class. Let’s also add a button to the XAML, and add a Click event handler that will close the window and exit the application. Here’s the XAML that we insert into the Grid element block.

    <Grid>
    <Button Grid.Column="0" Grid.ColumnSpan="1"
            Grid.Row="0" Grid.RowSpan="1"
            Width="75" Height="25"
            Name="closebutton"
            Click="OnCloseBtn">Close</Button>
    </Grid>

Since we’ve set the Click attribute to OnCloseBtn, we need to add an event handler of that name to the partial class defined in Window1.xaml.cs, as follows.

    public void OnCloseBtn(object o, RoutedEventArgs e)
    {
        Close();
    }

Okay, now if you compile and run the app, you’ll see a window with a button that says “Close” and if you click that, the app terminates. That’s good enough functionality there for a Hello World application I guess. So how does it all work? That’s what we’ll look at in the next section.

How the XAML and the C# code get compiled

Okay, let’s look at what happens during compilation. We’ll first look at the Window1 class. The XAML compiler parses Window1.xaml and compiles it into BAML (Binary Application Markup Language) which is a binary representation of the XAML (and is not in human-readable format). This BAML file will be inserted as a .NET resource into the generated assembly – and it’s this BAML file that will be referred to by the rest of the code.

A C# source file – Window1.g.cs – is also generated which contains a partial definition for the Window1 class. The contents of that file are as follows (I did reformat it for clarity) :

public partial class Window1 : System.Windows.Window,
    System.Windows.Markup.IComponentConnector
    {

        internal System.Windows.Controls.Button closebutton;

        private bool _contentLoaded;

        public void InitializeComponent()
        {
            if (_contentLoaded)
            {
                return;
            }
            _contentLoaded = true;
            System.Uri resourceLocater =
                new System.Uri("WpfHelloWorld;component\\window1.baml",
                    System.UriKind.RelativeOrAbsolute);
            System.Windows.Application.LoadComponent(
                this, resourceLocater);
        }

        void IComponentConnector.Connect(int connectionId, object target)
        {
            switch (connectionId)
            {
            case 1:
                this.closebutton =
                    ((System.Windows.Controls.Button)(target));
                this.closebutton.Click +=
                    new System.Windows.RoutedEventHandler(this.OnCloseBtn);
                return;
            }
            this._contentLoaded = true;
        }
    }

Okay, there are quite a few interesting things in that code snippet. For one, the class has implemented IComponentConnector which has two methods – InitializeComponent, which we had called from the constructor in the Window1.xaml.cs source file, and Connect. InitializeComponent uses Application.LoadComponent to load the BAML that has been embedded into the assembly as a .NET resource. LoadComponent internally uses XamlReader.LoadBaml and eventually, the internal class BamlRecordReader is used to read in the BAML, and it calls Connect on the Avalon object (in this case our Window1 object) for every element with a Name attribute that needs to be mapped with a member variable. In our example, notice how an internal Button member has been added to the class called closebutton. This closebutton variable is associated with the corresponding BAML element, and the Click handler is also properly hooked up. Connect is called once for each control that needs to be mapped to a XAML element. Now, the Window1.g.cs and Window1.xaml.cs files are compiled and a single Window1 type is generated in the MSIL (that’s how partial classes work).

Alright, that explained how the XAML for our window got associated with the code-behind file. Now, let’s look at the other XAML file we have – MyApp.XAML. There’s no BAML generated for this one, since there’s nothing to be stored really. But a MyApp.g.cs is generated which contains a partial definition for the MyApp class. Here are the contents of that file (with some reformatting) :

public partial class MyApp : System.Windows.Application
{
    public void InitializeComponent()
    {
        this.StartupUri = new System.Uri(
            "Window1.xaml", System.UriKind.Relative);
    }

    [System.STAThreadAttribute()]
    public static void Main()
    {
        Thread.CurrentThread.SetApartmentState(
            System.Threading.ApartmentState.STA);
        WpfHelloWorld.MyApp app = new WpfHelloWorld.MyApp();
        app.InitializeComponent();
        app.Run();
    }
}

Ah, there’s main! Notice the stress on setting up the COM threading model as STA, in fact there’s some redundant code there – both the attribute and the call to SetApartmentState. The MyApp object is instantiated, and InitializeComponent is called, which is defined in the same partial class, and merely sets the StartupUri property to Window1.xaml. This indicates that a Window1 window will be the main window for the application. Once InitializeComponent returns, Run is called, and internally the message loop is initiated and the window is shown.

Advertisements

5 thoughts on “Examination of a simple C# based Xaml app

  1. C# ? did i read well ? where is our favorite langage C++/CLI ? :p

    of course, except when using unmanaged c++ i can’t really find reason to use c++ instead of C# or VB.Net 😉 … but … is this really the end ? maybe your fed up with C++ cause of your book

    Best regards,

    Nico

  2. Well I am afraid a fell at the first hurdle.

    I installed all the requisites ages ago but never got round to creat any apps.

    I have installed WinFX Runtime Components 3.0 Beta 2 (Feb WinFx)
    Visual Studio 2005 Extensions
    WindowsXP-KB897696-x86-ENU.exe

    Whenever I create a new app I get the error message “Package Load Failure

    Package ‘PresentationDesignVisualStudio’ has failed to load properly ( GUID = {E58C2A8B-BCC4-4559-AD59-D62EB6D58A22} ). Please contact package vendor for assistance. Application restart is recommended, due to possible environment corruption. Would you like to disable loading this package in the future? You may use ‘devenv /resetskippkgs’ to re-enable package loading.”

    If I open up the references tree System.Security.Authorization reference has a /!\ symbol next to it

  3. Hi, I am Samrendra Kumar, currentely putting in New Delhi. I am working in a BPO as software d
    developer on DotNet2005, when I am searching about few topics to learn then i got ur web address
    and got happy to know that u r an indian. I shocked when read ur profile, u r programming at
    the age of 13 its just make me to confusious. I just learn about ur frnd lalu its true, because
    i was also pass from boys school.

    I am very glad to know about u.
    bye
    god bless u

    thanks
    samrendra
    +919911848669

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s