This is the part of WPF that, from as a Windows Forms (WF) developer for the past few years, I found most difficult to get my head around. However, once I’d actually read a bit up on this, it became second nature and I think is actually fairly intuitive – not to mention more flexible than the old WF way of doing things.
In Windows Forms, you tend to use absolute positioning as the way to layout your forms. Most controls are fixed in size at design time. There are some features that .NET provides to allow more flexibility – such as anchoring and docking. In addition, .NET 2 came with FlowLayout (which I hated) and Table (which I loved) containers. The Table one specifically, allows you to create consistent “grid-like” forms with Labels and Textboxes nicely aligned etc. It’s a little buggy but I’d rather have it than not! However, localisation of applications is difficult e.g. if a button text is too long etc. it can overflow the control.
WPF takes a completely different approach. There is no “anchoring” or “docking” like in WF. Instead, content can automatically resize itself to fit it’s container, depending on the size of the control and the settings of the parent. Instead of explicitly setting the width and height of a control, you can now simply use * to fit it to the container (actually, this is the default so if you don’t set the width it fits the container automatically), or “Auto” to set it to as big as required for its content. As the content changes, the size will automatically change. You’re discouraged from using absolutely positioning (although you still can) because it leads to a more rigid form which cannot easily change. WPF comes with several container controls which your controls (buttons etc.) live inside:
The Stack Panel places items either vertically or horizontally on top of one another. In this example, the Stack Panel contains four controls – a Label, two buttons, and a progress bar. Notice how the buttons and progress bar automatically resize themselves to fit the width of the panel.
The Wrap Panel is similar to the FlowLayout container in WF – it arranges items in a list horizontally. When they reach the end of the panel, they wrap onto the next line. In this example, the Wrap Panel contains those same four controls – I’ve set the width of the Progress Bar to 100 units wide. As the four controls can’t all fit on one line, the Close button and Progress Bar and pushed onto the next one. Notice how the Buttons now size to fit their content text.
The Dock Panel decorates child controls with a Docking property that allows you to dock them to a particular side of the Dock Panel. In this example, I’ve docked the Label to the Top, the buttons to the left and right, and the progress bar to the bottom. You have to be careful of the order that items appear in the XAML so that they dock as you intend e.g. in this example, the Label comes before the buttons in the markup. If it came after them, the OK and Cancel would extend all the way to the top of the panel and the label would have been surrounded by them. Think of it almost like the “bring to front” feature in Windows Forms.
Think of the Grid container as a better version of the Table container found in WF. It allows you to create rows and columns and place controls inside them, just like the Table. However, it requires less effort to achieve similar results. It’s probably the most useful container control, and it’s the default one you work with whenever you create a new Window in VS 2008. In this example below, I’ve created a 3×3 grid. The middle column has it’s size set to “Auto”, meaning it’s width is equal to the minimum required by its child objects i.e. the OK button. The middle row is set to 50 units high for the Progress Bar. I’ve also set the Column Span for the Label to 3 columns so that it goes all the way across. The designer support for Grids is pretty good – so I’ve got screenshots of both the Grid running and in the designer (taken from VS2008 Express).
The columns and rows are draggable within the designer to quickly resize them if necessary; you can also see the sizes from the numbers on each row/ column, and get semi-transparent grid lines to help you keep focus of where you are in the grid. All of this disappears if you’ve not selected a control within the Grid. Nice. Note that in the running version of the Grid I’ve explicitly left the gridlines on – these are turned off by default.
This lets you use absolute positioning for items within the Canvas. I’m not going to talk much about this as I’ve not used it really and, again, the recommended approach is to not use absolute positioning in your Forms. There’s no Anchor or Docking facility with WPF like in Windows Forms if you’re in the Canvas.
Apart from the Canvas, all the others work by position their contents relatively to one another – so if one changes size, all the others automatically resize and reorder themselves as appropriate.
I found it a bit unusual designing a form like this but once I got the hang of it I realised the benefits of such an approach: You tend to spend more time getting the layout correct, and then placing controls inside them. Once you’ve done this, your form almost seems to “magically” arrange itself – you don’t get the problems as in WF where adding a new control later on requires all sorts of re-ordering and resizing of the existing controls.