Click here to Skip to main content
Click here to Skip to main content

WPF Windows: Code-based layout versus XAML

, 12 Aug 2006
Rate this:
Please Sign up or sign in to vote.
Designing your windows from code has suffered from the introduction of WPF and its XAML. Nevertheless it is possible not to use the descriptive language at all. Lets see how.

Introduction

With WPF, Microsoft introduced a new XML based descriptive language for use when designing interfaces called XAML. To help you use the new language, the company built in the VS forms designer support for XAML. Also, the Microsoft Expression Interactive Designer can be used to create such files.

But how about code-based layout? How did it change? Charles Petzold seems to think that it was left out from WPF layout improvements and designing code-only interfaces has now become harder than ever. Let's see if he is right.

Possible uses of this non-XAML approach in WPF are:

  • you do not know XAML, have experience with .NET 2.0 and need fast results
  • VS does not offer XAML support for the type of project you are working in (any .NET 2.0 project type at the moment)
  • you want to dynamically (at runtime) create a window, it changes too much to use a single XAML for all configurations and don't want to use multiple XAML files
  • you want to dynamically (at runtime) add only a few controls to an existing XAML window

Prerequisites

To understand the code, you should have a basic understanding of XAML and WPF layout using XAML. If you have experience dynamically creating .NET 2.0 forms using code, it's even better.

Using the code

The code was written in VS 2005 with the June CTP of .NET 3.0 installed, it might not work with another CTP. It contains an example of code-only WPF window layout in a .NET 2.0 class library project, being used in a .NET 2.0 EXE application.

Changes in WPF layout from .NET 2.0

First of all, WPF made standard the resolution-independent way of designing Windows. In .NET 2.0 you had to manually position each control on the screen using co-ordinates and you could, with a certain amount of additional work, use resolution independent panels. In WPF, panels are the standard way of doing things so you should understand them well. A Form can hold only one child object, in its Content property. You could add a normal control there, but then you cannot add any other control on your form. That is why the Forms Content object should be a control Container, that is a control that can hold other controls. Containers designed and shipped in WPF for this purpose are: Canvas, Grid, StackPanel, and DockPanel. They provide different ways to arrange your controls on the form.

General steps in creating a WPF window from code

We will use a normal .NET 2.0 class project to create our WPF window in. Before we start, we should make sure we have all the prerequisites listed. Then, as we are not going to use a .NET 3.0 type of project, we must add references to the used assemblies. A reference is created by right-clicking on the References directory in your Solution Explorer. Then select Add Reference, then .NET. Add these DLLs: PresentationCore, PresentationFramework, and WindowsBase. They contain the objects we need from .NET 3.0. Now we can start coding in a new class file added to your project (Right click on your project in Solution Explorer, Add-> New->Class).

  1. Inherit from the Window class. You want to add extra functionality to a blank WPF window. It is only natural to derive from it, like this:

    public class StackPanelWindow:System.Windows.Window
  2. Declare the controls you want to use:

    StackPanel stack;
    Button btn;
    TextBox text;
  3. Create a constructor for the derived class in which you set the window's Width and Height:

    public StackPanelWindow()
    {
        this.Width = 300;
        this.Height = 150;
  4. Instantiate the Panel and set its Width and Height:

        stack = new StackPanel();
        stack.Width = this.Width;
        stack.Height = this.Height;
  5. Instantiate one of the declared controls and set its Width, Height, other useful properties and events:

        text = new TextBox();
        text.Width = 100;
        text.Height = 20;
        text.Text = "some text";
  6. Add the control to the Container.

        stack.Children.Add(text);
  7. Set the control's positioning. This part is dependent on the panel that you use. Generally, it is something like:

        Class.SetXXX(control_to_set,value);
  8. Use the window in your program like this:

        CodeWindows.StackPanelWindow sw = new CodeWindows.StackPanelWindow();
        sw.Visibility = System.Windows.Visibility.Visible;

Layout example with StackPanel

The StackPanel allows you to add items to the Window just as you would add a plate on top of another plate, creating a stack of controls. Keep in mind that the last control added is the one you see at the bottom of the form, controls are added one under the other.

public class StackPanelWindow:System.Windows.Window
{
    StackPanel stack;
    Button btn;
    TextBox text;

    public StackPanelWindow()
    {
        this.Width = 300;
        this.Height = 150;

        //add the StackPanel
        stack = new StackPanel();
        stack.Width = this.Width;
        stack.Height = this.Height;
        this.Content = stack;

        //add the text field
        text = new TextBox();
        text.Width = 100;
        text.Height = 20;
        text.Text = "some text";
        stack.Children.Add(text);

        //add the button
        btn = new Button();
        btn.IsEnabled = true;
        btn.Width = 100;
        btn.Height = 20;
        btn.Content = "Say it!";
        stack.Children.Add(btn);
    }

We see that step 7 is missing; the controls are automatically positioned one under the previous one.

Layout example with DockPanel

The DockPanel is a Panel in which each control is docked (that is, it sticks to a part of the Panel). The code is the same as the one with StackPanel but now we have to set the position of the controls manually by docking each one, like this:

    DockPanel.SetDock(text, Dock.Top);
    DockPanel.SetDock(btn, Dock.Bottom);

If we add a fifth control and so there is no side to dock it, it can be fitted in the center.

Layout example with Grid

The Grid is like a table. It has rows and columns in which we can position controls. First we create the Grid structure - the rows and the columns:

    //create two columns
    grid.ColumnDefinitions.Add(new ColumnDefinition());
    grid.ColumnDefinitions.Add(new ColumnDefinition());

    //and two rows
    grid.RowDefinitions.Add(new RowDefinition());
    grid.RowDefinitions.Add(new RowDefinition());

Then to position each control in the Grid:

    Grid.SetColumn(text, 0);
    Grid.SetRow(text, 0);

Layout example with Canvas

The canvas was the standard .NET 2.0 way of doing things. It allows you to position each control on a canvas with precise co-ordinates, like this:

//inherit from the WPF Window object
public class CanvasWindow:System.Windows.Window
{
    private Canvas canvas;
    private TextBox text;
    private Button btn;

    public CanvasWindow()
    {
        //first, set the window properties
        this.Width = 300;
        this.Height = 150;

        //add the canvas
        canvas=new Canvas();
        canvas.Width = this.Width;
        canvas.Height = this.Height;
        this.Content =canvas;

        //add a  text field
        text = new TextBox();
        text.Width = 100;
        text.Height = 20;
        text.Margin = new System.Windows.Thickness(10,10,10,10);
        text.Text = "some text";
        text.KeyDown += new System.Windows.Input.KeyEventHandler(text_KeyDown);
        canvas.Children.Add(text);

        //add a button
        btn = new Button();
        btn.IsEnabled = true;
        btn.Width = 100;
        btn.Height = 20;
        btn.Content = "Say it!";
        btn.Margin = new System.Windows.Thickness(110, 10, 10, 10);
        btn.Click += new System.Windows.RoutedEventHandler(btn_Click);
        canvas.Children.Add(btn);
    }

The positioning was made by this line:

    Control.Margin = new System.Windows.Thickness(10,10,10,10);

which is a general way to make sure your object is where it should be. If you want to use another approach, particular to the Canvas object, use:

    Canvas.SetLeft( control_in_canvas , value );

and

    Canvas.SetTop( control_in_canvas , value );

Note that layout created using the Canvas is not resolution-independent, as all the properties are in pixels. It is not recommended to use it if you do not need it.

More Complex Design

For mode complex design, the panels should be used one in another. An example is: use a Stackpanel in a DockPanel to have several elements on the side of the DockPanel.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Dragos Sbirlea
Software Developer
Romania Romania
Dragos is currently a student at the Polytechnic University of Bucharest. He likes keeping up to date with new and amazing technologies and he hopes he will one day master the mechanisms behind modern day programming languages so that he can write the best possible code from a performance and maintainability point of view.
 
He keeps track of the things he learns on a daily basis on his blog, at http://picobit.wordpress.com/ .

Comments and Discussions

 
Questionimage please? Pinmemberdonsolms30-Jun-07 10:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140902.1 | Last Updated 12 Aug 2006
Article Copyright 2006 by Dragos Sbirlea
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid