Feeds:
Posts
Comments

Archive for May, 2006

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.

Read Full Post »

C++/CLI in Action

Some of you already know about this, but I have been working on a C++/CLI book for Manning Publications for the past five months or so. The book is titled “C++/CLI in Action” and is targeted at Visual C++ developers with a .NET background who’d like to interop their native code with managed frameworks. The first part of the book discusses the C++/CLI language and semantics, the second part moves into mixed-mode programming techniques, and the third part covers specific managed frameworks and how to interop with them from native code.

There are chapters dedicated to mixing MFC with .NET, Windows Forms and MFC interop, interoping with Avalon (Windows Presentation Foundation), and interoping with Indigo (Windows Communication Foundation) including migrating DCOM based applications to Indigo. Of course, the WinFX coverage is futuristic in nature since the frameworks are still in an advanced Beta stage. The book is currently scheduled for a Sep/Oct 2006 release, and in a couple of weeks, I’ll be submitting the first draft of the final manuscript for editing and review.

It’s been a lot of hard work, especially since I have a fulltime day-job, and I’ve been doing an extra 25-35 hours every week just for the book (and that’s in addition to my 40 hours at work). I just hope that readers will benefit from the long hours of R&D I have put into the book. In future blog entries, I’ll write more details of the book’s nature and structure.

Read Full Post »

I’ve been playing with Indigo (Windows Communication Foundation), and was fairly impressed with its support for duplex communication. With the help of my good friend and Win32 Guru Rama Vavilala, I also managed to get a DCOM sample working that used connection points for duplex communication via event sinks. Not only was the DCOM app complicated to write, but I had to change security settings and disable the XP firewall before it worked across the network. In WCF, you’d just have to choose an HTTP binding that supported duplex communication. So, while WCF is impressive on its own right, unless you’ve done some DCOM, you won’t understand its greatest strength – implementation simplicity!

Read Full Post »

Follow

Get every new post delivered to your Inbox.