Introduction

Some of you may have come across some of my other articles that I have published here on The Code Project. And if you have, you may have noticed that I have been writing a few on WPF/LINQ/Silverlight/WCF of late. Generally, I try and have fun when I write my articles, and I try to make them interesting for myself; now sometimes, that means that they end up being quite complex, which I like.

However, I remember not so long ago, I had published what I deemed to be an intermediate level WPF article, which due to The Code Project upgrade, got classified as beginner. It was never intended to be a beginner's article, so it got some stick from some folk, for being too complicated and not beginner-esque.

Now, I don't mind getting stick, but this time, it was due to an upgrade problem, not something I had done. It did, however, get me thinking about what one of the forum entries stated: "Where are all the beginner's articles on WPF?"

So I thought about this, and did a search here on The Code Project, and found that generally, WPF writers on The Code Project (me included) are pretty much showing off. Now, don't get me wrong, this is a good thing; I can't tell you how much I've learnt from some of the more showy-offy type articles. But I also thought that there wasn't that much here for beginners with not much time on their hands... so I thought, yeah, perhaps a beginner's series in WPF would be nice. I know Josh Smith did a bang up job with his series A Guided Tour of WPF, which I personally recommend you all read if you haven't already.

And there are always books, but I've got three books on WPF and they all have differing information. So I thought, OK, maybe this beginner's series may not be so bad after all. I decided to give it a crack. I don't know how many articles I'll end up doing for this series, but it will probably be something like:

Like I say, I think Josh did an excellent job covering a lot of this, but why then did I buy three WPF books, was one not enough? Sometimes, it's just nice to have a different point of view. For example, Josh is a WPF master (a condor if you like... or some equally majestic bird... huge black out in the sun, wing spanned bird), and I am a fledging chick just learning to fly (with tiny little wings) in the WPF world. So I figure it may do some people some good, to hear things from a slightly different angle (A.K.A. crazy fledging chick).

I will, of course, be covering some stuff that you could lift straight out of a book, but I hope there will also be some new stuff that I have picked up whilst taking my own WPF journey.

As this series will be quite a commitment, all I ask is that if you find this article useful, please leave a comment at the bottom and a vote, so I know whether it's worth doing the rest of the series. You know there are 100s of other articles in my reserve (I have a big list), where I could go mad, but I feel that this may be a useful series (basically, tell me in the article's forum that you want more of this), and if that is the case, I will be more than happy to commit myself to making this series as enjoyable as I can.

So without further ado, I guess we should start looking into what we need to get to grips within this article. As it is the first article in this (proposed, if people want more of this) series, it really has to start with layout.

Layout

Layout is one of the most important parts of any WPF project; the following sub sections will introduce you to the new layout options at your disposal.

The Importance of Layout

The way I see it, WPF can be used in one of two ways, it can be used in a browser (partial trust) - these are known as XBap, or a full blown application, basically an executable (*.exe). Whatever format is chosen is not important for this article's content, as layout is equally important to both formats.

What I mean is that layout is a fundamental building block used when writing any WPF, no matter whether it's an XBap or an application. Using the layout controls in WPF allows developers/designers to create very complex arrangements of pages/controls. Without layout, we probably couldn't achieve anything, apart from a mess. So if you are looking for a mess, just quit reading right here. If, however, you want to know how to use the new layout options in WPF, read on.

What's New in WPF

If you are a Web developer, probably most (but not all) of what this article is going to cover will be new to you. If you are a WinForms developer, you have undoubtedly come across Panel classes before, and maybe even used some of the more sophisticated Panel sub classes, such as FlowLayoutPanel and TableLayoutPanel. You should also be familiar with WinForms properties such as Anchor and Dock. Sounds familiar? Well, the truth is that some of this knowledge will still be useful, but you will still have to do some learning. For you Web guys, the good news is that the XAML syntax is fairly similar to XHTML, so you shouldn't have any trouble picking up this new way of creating UIs either.

Within WPF (at least the current version), Microsoft has provided a few Layout controls for developers/designers to use, most of which will be new ground to most of you, I imagine. These new layout controls will be the main focus of this article. You are, of course, free to author your own layout controls, if one of the pre-built controls doesn't suit your needs. We will see more on this later.

For the purpose of this article, we will be looking at the following:

Canvas

StackPanel

WrapPanel

DockPanel

Grid

Please note that I will only be covering the basics of these controls; there are many more resources available for being clever with these controls, should you wish to research that. I however, consider the more advanced usages of these controls to be outside the scope of this article. Remember it's a beginner's series, so I want to keep it at a beginner's level.

A Brief Detour into the Importance of Margin

One thing that you simply must know, is how important the Margin property is. By using the Margin, we are able to specify how much space the current control (the one we are specifying the Margin property for) wants to have around it. WPF provides a ValueConverter that accepts a string of the format 5,5,5,5, but what does this mean? Well, it's basically saying that we want a Margin of 5 pixels all around the control that is declaring this property. The Margin string is stating Left, Top, Right, Bottom, and is one of three overloaded constructors used by the strangely named Thickness class that is used in the case where we are trying to set the Margin in code-behind.

Canvas

The Canvas control is one of the easier layout controls to use. It is a simple X/Y position container, where each of the contained (children) controls must specify the following four properties in order to be positioned within the parent Canvas control:

Canvas.Left

Canvas.Right

Canvas.Top

Canvas.Bottom

With these four properties in place, the control will be positioned using these values within the parent Canvas control. These properties probably look a little bit odd, where we have a Canvas.Left for example; well, they are a bit odd actually. These are not the normal properties that you used in .NET 2.0 land. These are Dependency/Attached Properties, which I am not going to go into right now, as they will be the subject of a further article in this series.

What else do we need to know about a Canvas control and its children? Well, actually that's almost it; the only other thing to consider is that if the Canvas control is a simple X/Y position container, what's to stop two child controls, overlapping, and which child control should be on top? Well, that's all taken care of by another Dependency/Attached Property of the Canvas control. This is called the Canvas.ZIndex property, and this indicates which control should be on top. Basically, the higher the Canvas.ZIndex value is, the more on top the control that declares this Dependency/Attached Property will be. If no Canvas.ZIndex is declared for any of the child controls, Canvas.ZIndex will be set to the order in which the children are added to the Canvas control.

Let's see an example of this, shall we? The following picture shows a Canvas control with two children, one on top of the other. This is taken from the file called CanvasDEMO.xaml in the attached demo project.

StackPanel

The StackPanel control is also very easy to use. It simply stacks its contents, vertically or horizontally, using a single property called Orientation.

Let's see an example of this, shall we? The following picture shows a StackPanel control with two children, one on top of the other. This is taken from the file called StackPanelDEMO.xaml in the attached demo project.

So how does this look in code? Well in XAML, it is as follows:

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="WPF_Tour_Beginners_Layout.StackPanelDEMO"x:Name="Window"Title="StackPanelDEMO"WindowStartupLocation="CenterScreen"Width="640"Height="480"><StackPanelMargin="0,0,0,0"Background="White"Orientation="Vertical"><ButtonContent="Im Top of Stack"/><ButtonContent="Im Bottom Of Stack"/></StackPanel></Window>

DockPanel

The DockPanel control is one of the most useful (in my opinion) layout controls. It is the one that we would probably use as the base layout control that any new Window uses. Basically, with a DockPanel control (or two), we can achieve the sort of layout that has been the main layout for most applications we have ever seen. We can basically get a menu docked to the top, then a left/right main content area, and a status strip at the bottom. This is all thanks to a couple of properties on the DockPanel control. Basically, we can control the docking of any of our child controls that is within a parent DockPanel control by the use of the following Dependency/Attached Property.

DockPanel.Dock

This property may be set to Left/Right/Top/Bottom. There is one further property exposed as a normal CLR property on the DockPanel control, which is called LastChildFill, which when set to true will make the last child control that was added to the DockPanel control fill the remaining available space. This will override any DockPanel.Dock property that the child control may have already set.

Let's see an example of this, shall we? The following picture shows a DockPanel control with two children, one docked to the top, and the other docked to fill the remaining available area. This is taken from the file called DockPanelDEMO.xaml in the attached demo project.

Grid

The Grid control is by far the most sophisticated WPF layout control there is (at present). It is sort of like an HTML table control, where you can specify rows and columns, and have cells that span multiple rows, or cells that span multiple columns. There is also a strange syntax which may be used for the width/height of columns and rows, which is known as the star "*" notation, which is exposed through the use of the GridLength class. Think of this as being like a percentage of what's left divider. For example, I could have some markup such as:

Where I have declared three Grid ColumnDefinition controls, where the first ColumnDefinition gets a fixed width of 40 pixels, and the remaining space is divided between the last two ColumnDefinition controls, where the last one gets twice as much as the second last one. This is the same principle for RowDefinition.

In order for child controls of a Grid control to tell the WPF layout system which cell they belong to, we simply use the following Dependency/Attached Properties, which use a 0 based index.

Grid.Column

Grid.Row

And to specify how many rows or columns a cell should occupy, we simply use the following Dependency/Attached properties, which start at 1.

Grid.ColumnSpan

Grid.RowSpan

By clever usage of a Grid control, you should almost be able to mimic any of the other layout controls. I'll leave that as an exercise for the reader.

Let's see an example of the Grid control, shall we? The following picture shows a Grid control with three columns and a row, where there are two children. The first child occupies column 1, and the second child occupies columns 2-3 as its Grid.ColumnSpan is set to 2. This is taken from the file called GridDEMO.xaml in the attached demo project.

As I say, the Grid control is quite sophisticated, so I urge you to explore this one further. You can do all sorts of things with the Grid such as have GridSplitter controls for resizing columns/rows, and you can set up shared sizes across multiple grids; this is known as SizeGroup. So please explore the Grid control further.

Putting it all Together

So now we can put all this good knowledge together and we could create something as beautiful as this:

No... only joking, I think the best thing to do here is, let's say I have some hypothetical layout that I want to achieve. Let's say one of the common layouts, favoured for years, where we have a menu bar at the top, followed by a main content area, and a status bar area at the bottom. Let's see a mock up (designed as a simple WinForm) of what we are aiming for:

I think I have given you all the tools you need to carry out designing this sort of layout in WPF. Do you want a hint, I think you will need to use the StackPanel, DockPanel, and Grid controls in order to get the job done.

In case you are wondering (lost **** it), here is how I did it (XAML only this time, sorry folks):

<Windowx:Class="WPF_Tour_Beginners_Layout.PuttingItAllTogether"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"WindowStartupLocation="CenterScreen"Title="PuttingItAllTogether"Width="640"Height="480"><DockPanelWidth="Auto"Height="Auto"LastChildFill="True"><!--Top Menu Area--><MenuWidth="Auto"Height="20"Background="#FFA9D1F4"DockPanel.Dock="Top"><!-- File Menu --><MenuItemHeader="File"><MenuItemHeader="Save"/><Separator/><MenuItemHeader="Exit"/></MenuItem><!-- About Menu --><MenuItemHeader="Help"><MenuItemHeader="About"/></MenuItem></Menu><!--Bottom Status Bar area, declared before middle section,
as I want it to fill entire bottom of Window,
which it wouldn't if there was a Left docked panel before it --><StackPanelWidth="Auto"Height="31"Background="#FFCAC5C5"Orientation="Horizontal"DockPanel.Dock="Bottom"><LabelWidth="155"Height="23"Content="Status Bar Message...."FontFamily="Arial"FontSize="10"/></StackPanel><!--Left Main Content area--><StackPanelWidth="136"Height="Auto"Background="White"><ButtonMargin="5,5,5,5"Width="Auto"Height="26"Content="button1"/><ButtonWidth="126"Height="26"Content="button2"Margin="5,5,5,5"/><ButtonWidth="126"Height="26"Content="button3"Margin="5,5,5,5"/></StackPanel><!--Right Main Content area, NOTE HOW this Grid is the last child
so takes all the remaining room --><GridWidth="Auto"Height="Auto"Background="#FFCC9393"><Grid.ColumnDefinitions><ColumnDefinitionWidth="*"/><ColumnDefinitionWidth="*"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinitionHeight="*"/><RowDefinitionHeight="*"/></Grid.RowDefinitions><RectangleFill="Aqua"Margin="10,10,10,10"Grid.Row="0"Grid.Column="0"/><RectangleFill="Aqua"Margin="10,10,10,10"Grid.Row="0"Grid.Column="1"/><RectangleFill="Aqua"Margin="10,10,10,10"Grid.Row="1"Grid.Column="0"/><RectangleFill="Aqua"Margin="10,10,10,10"Grid.Row="1"Grid.Column="1"/></Grid></DockPanel></Window>

Which resulted in the following Window:

There are a couple of tricks here, namely the following:

The Grid for the right hand content area must be the last child declared in order for it to take up the remaining space that the parent DockPanel wants to fill, due to LastChildFill="True".

The StackPanel used for the status bar must be before any other child that is declared as being DockPanel.Dock="Left" or DockPanel.Dock="Right". As, if there was another element before the status bar StackPanel, the status bar StackPanel would not be able to span the entire width available, as this space would have been stolen by any child that was DockPanel.Dock="Left" or DockPanel.Dock="Right". Try it, you'll see what I mean. Simply move the status bar XAML further down in the XAML file, say to the end.

Performance Considerations

As some panels can be bound to items (this will be discussed further in the DataBinding article), there may be occasions where the number of child elements displayed in a panel is quite large. For example, if a StackPanel contains a ListBox that is bound to a large database query, there would be lots of items. In this case, it's the ListBox that will have lots of children. However, internally, the ListBox control uses a Vertical StackPanel to render its items by default. Mmmm, that's not so great.

However, all is not that bad. WPF has one further trick up its sleeve to aid in this situation. We can use the Dependency/Attached Property VirtualizingStackPanel.IsVirtualizing on a ListBox, which means that the ListBox control's internal StackPanel rendering its items will now be virtualized. But what the heck is a VirtualizingStackPanel?

When a panel is virtualized, it means that only the visible elements are created. The rest aren't displayed. For example, when creating a ListBox displaying images bound to a database holding 100,000 rows, it would take a long time for the ListBox to load. If you use a virtualize panel, then only the visible images will get created in the UI. When you scroll down, the currently visible items will get destroyed, and the new visible items will get loaded onto the UI. There is only one panel that supports virtualization, and it is the VirtualizingStackPanel. If you need to create any new virtualized panels, you will have to write your own.

Custom Layouts

It's also possible to create your own custom panel which performs all types of custom layouts.

Now I could try and be clever here, and come up with some new spin on how to do this, but Paul Tallet has already done a great job here, with a section in his great FishEye panel CodeProject article. So this next little section's words are thanks to Paul Tallet:

To get your own custom panel off the ground, you need to derive from System.Windows.Controls.Panel and implement two overrides: MeasureOverride and LayoutOverride. These implement the two-pass layout system where during the Measure phase, you are called by your parent to see how much space you'd like. You normally ask your children how much space they would like, and then pass the result back to the parent. In the second pass, somebody decides on how big everything is going to be, and passes the final size down to your ArrangeOverride method where you tell the children their size and lay them out. Note that every time you do something that affects layout (e.g., resize the window), all this happens again with new sizes.

There is a whole bunch of custom panel links over on Rob Relyea's blog here.

We're Done

Phew, that was a lot to go through I suppose, but I hope by now you have the basics of layout in WPF.

But... Like I Said, If You Want More...

As I stated earlier, this article series is a big commitment for me, so if you want more, please vote, and leave a message so I know that it's worth me doing a whole series like this, at this level.