The WPF layout strategy is much more "web" like than WinForms, where
everything is coordinate based. WPF uses a "Flow" layout paradigm that
requires an almost completely reversed thought process. However, before we
dive into the various layout controls in WPF, we need to cover some of the
Elements, Controls, and Content, Oh My!
Every visual item in WPF is an Element, Elements that can receive focus and
interact with the user are called Controls (unlike WinForms, where everything is
a control). There are three main types of Controls:
- ContentControls - Controls that can hold only one piece of content.
This includes the Window, TextBox, etc. Note: That one piece of
Content can also be a Panel or an ItemsControl.
- ItemsControls - Controls that can hold a list of items. These include
the ListBix, TreeView, etc.
- Panels - Controls that can hold one or more children and visually
arrange them according to predefined rules. These include the Grid,
WrapPanel, StackPanel, and others.
Layout starts with the Window. The first significant change is that a
WPF Window can only contain a single element. Typically this single piece
of content will be a Panel (otherwise you couldn't do much with the Window!)
And, more often than not, that Panel will be a Grid. So much so that the
default Window template in Visual Studio contains a Grid as the Panel.
ContentControls are extremely versatile in WPF, much more so than in
WinForms. The Single Piece of Content restriction isn't much of a
restriction, since that single price of content can be another ContentControl,
an ItemsControl, or even a Panel. (The only item that isn't allowed is a
Window, since it must be the top most control in the hierarchy.
It's all "relative"
When placing controls into a container in WPF, the process is very different
than in traditional WinForms. Items do not (at the very least should
not) specify coordinates, or even a specific size. Items are
arranged by order and (requested) size. Items aren't even guaranteed to
get their requested size if the container can't fulfill it. It's kind of
like the '60s commune type of thing, with everyone just happily co-existing
:-)...not really, well, yes, really, but it's a good thing, as we will see.
Layout is a two phase process, where the first pass measures everything,
taking into account minimum and maximum dimensions, and then the second pass
arranges all of the controls. If the container has enough space (the
commune is large enough), everyone gets a seat at the table. If there is
enough size for all of the controls preferred size, everyone gets their
preferred seat at the table. If the container does not have enough space,
items will be truncated to fit.
Interestingly enough, the Height and Width properties don't necessarily
reflect that actual size of a control. They reflect the requested
dimensions. The ActualHeight and ActualWidth properties reflect that
actual rendered dimensions of a control.
The Simple Containers
Although fairly simple, the StackPanel, WrapPanel and DockPanel all have
their uses. Typically they will be nested within another container, but
there could be instances where they are the first descendent in a Window. .
The Stack Panel
The StackPanel will stack items vertically (top down) or horizontally (left
to right) within it's walls. Setting the "Orientation" property determines
the direction. Either way, it's a single column(row) of items.
The Wrap Panel
The WrapPanel lays out it's contained controls in a single row(column) until
it runs out of space, then wraps the remaining items onto the next row(column).
The Orientation property again determine if the items go into rows(Horizontal)
The Dock Panel
The DockPanel will be more familiar to WinForms developers. It will
Dock controls against one of it's edges, or "Fills" the remaining space.
Of the more powerful containers, the Grid will probably be the most prevalent
Panel in WPF applications. Grids separate themselves into cells defined by the
Rows and Columns of the grid. Typically each cell will contain one element.
Since that element can be a Panel or other layout control, the possibilities are
To add Rows and or Columns to the Grid, you can click in the margin in the
designer, or add them by hand in the markup. Either way, RowDefinitions or
ColumnDefinitions tags will be added (if you only have one Row(Column) the
RowDefinitions(ColumnDefinitions) tag is optional).
There are three methods for sizing Rows/Columns:
- Absolute Sizing - specific size is specified in device independent units
(remember, not a good idea in WPF)
- <RowDefinition Height="22"></RowDefinition>
- Automatic Sizing - content determines the appropriate size
- <RowDefinition Height="Auto"></RowDefinition>
- Proportional Sizing - space is divided appropriately.
- <RowDefinition Height="*"></RowDefinition>
Keep in mind that everything is a request, sizes aren't guaranteed.
That being said, however, the most interesting of the options is proportional.
Proportional rows will take up whatever space is left over after the Absolute
and Automatic Rows(Columns). If there are more than one Row(Column) set
for proportional, they will split the available space. You can also use
modifiers to weight the sizing:
In the above example, the first column will get 25% of the space, and the
second column will get 75%.
Detour: Attached Properties
Attached Properties allows for extending WPF controls/elements simply through
Markup. Certain containers will appear to add properties to
objects they contain. These attributes appear in the format of
DefiningType.PropertyName (e.g. Grid.Row). When a TextBox is added to a
Grid, the cell the TextBox is in is defined in the TextBox's markup.
In addition to specifying the Row and Column, the Grid exposes RowSpan and
ColumnSpan attached properties also. These work similar to their HTML
Back on Track: Additional Grid Features
The GridSplitter allows for runtime resizing of Rows or Columns. The
enables creating of windows similar to Windows Explorer with resizable portions.
Shared Size Groups allows for a Row(Column) in one grid to be synced with a
Row(Column) in another Grid.
There is WAY too much info in WPF to discuss all of the layout options in a
single post. Hopefully, this is enough to get you started on the path.