Commonly used Panels in WPF

In the previous tutorial, we learnt how to create a simple application using the DockPanel. In this tutorial, we will learn about application layouts and the support that WPF provides to arrange controls in a good layout using different types of panel controls. So far, we have learnt about creating basic WPF programs, adding controls and properties. We also already know about simple controls like buttons and textboxes. Remember, a control is something that derives from System.Windows.Controls.Control base class. Most elements that you come across in a WPF UI are controls. The base class in turn derives from System.Windows.FrameworkElement base class, which provides them with framework-level set of properties, events, and methods. The properties help in fine-tuning their positioning and appearance. For example, margin and horizontal/vertical alignment are some properties.

But haphazardly arranging the controls is not going to lead to a good application no matter how correctly or intelligently you add the controls or how much you attempt to control their positioning. Fortunately, as we learnt in tutorial 1, WPF has built-in intelligent layout capabilities to arrange the visual elements of an application. Before beginning to experiment further with the intelligent layout capabilities of WPF, it is important to understand about panel controls that play a large part in helping you arrange other controls efficiently. We will now learn about different panel controls and see the usage of some of the most commonly used panels.


When it comes to application layout, different controls are typically arranged within a layout using Panel controls. We have already used the DockPanel control in previous tutorials. It is one of the various types of “Panel” controls. They are controls that are capable of holding other controls for efficient visual representation on the screen. In other words, they control the rendering of the elements in terms of aspects like size, position, arrangement etc. Similar to other controls, they are derived from System.Windows.Controls base class. Some other panel controls include Grid, StackPanel, WrapPanel, Canvas and TabPanel. There are also nested panels using which you can place panels inside panels for complex arrangements.

All the panel controls are derived from the “Panel” base class. These provide many properties and methods that allow the creation of complex layouts. WPF also provides the ability to create custom panels. Basically, developers can override the ArrangeOverride and MeasureOverride methods in Panel class to design their own panel control behavior but more of that later. For now, we will be using the built-in panel controls. Before proceeding further, it might be useful here to give a brief description of the most commonly used WPF panel controls so here you are:

  • DockPanel: This provides an area within which you can “dock” child elements horizontally (default) or vertically relative to each other. When you “dock” an element to the top, it takes up the entire top bar, so the remaining elements will be places in the rest of the area below it, and so on. This is useful when you want to say, “dock” the main menu at the top of the screen and use the remaining space for dynamic pages.
  • StackPanel: This allows the arrangement of elements in a single line either vertically (default) or horizontally. It basically “stacks” elements one on top of the other. WPF also provides a performance-optimizing StackPanel called “VirtualizingStackPanel”, which generates a subset of elements from a larger set depending on whether the element is visible on screen on not. By generating only the elements that are visible on screen, the performance is optimized. For instance, suppose there are 1000 items in an ItemsControl (a simple control that displays a collection of items). Instead of generating all of them at once, the VirtualizingStackPanel generates only those that are visible on screen, and generates new ones as and when the user scrolls down.
  • Grid: This provides an area similar to a matrix with rows and columns. You can place the child elements in precise positions by defining the row and column numbers.
  • WrapPanel: A WrapPanel is similar to a StackPanel in that it stacks child elements horizontally or vertically, the difference being that it does not do so within a single line. If space is not enough, the panel “wraps” the elements such that they go on to the next line. So if you resize the window, the elements may go on to the next line. Also, while StackPanel stacks elements vertically by default, WrapPanel does so horizontally by default.
  • Canvas: This provides an area in which you can place child elements by specifying x and y coordinates in relation to the canvas area. A canvas must have exact height and width, and its child elements must have exact positions.
  • TabPanel: It provides an area to manage tab buttons of a “TabControl” class. This class is used to manage a set of tabbed pages. Each page can again consist of several controls arrange with or without panels.

Ok, so now that we have a basic idea about different panels, we can start using them. We already saw the usage of DockPanel in the fontviewer application. We will now see how to use two of the other most commonly used controls to manage application layouts. These are: Grid and Stackpanel. So let us use these to modify the FontViewer application.

If you remember, when we created the FontViewer application, we had deleted the Grid and put a DockPanel there instead. Now, let us do the reverse. We will replace the DockPanel with a Grid as shown: <Grid></Grid>.

When you use a Grid with multiple elements, it becomes necessary to use rows and columns to avoid elements overlapping each other. So, let us now define three rows and two columns. The syntax to do it is by defining ColumnDefinitions and RowDefinitions as shown:

<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=”25px”></RowDefinition>
<RowDefinition Height=”45px”></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>

As you can see above, we have also defined the height for the first two rows. This is so that the text and the combobox do not take up a lot of space and leave it for the ListBox which needs the space. As mentioned earlier, these properties are coming from the FrameworkElement base class.

Now when we are giving the first TextBlock at the top, the one that has tells the user to select an item from the list, we want it to span across both the columns. So we define a property for it like this Grid.ColumnSpan=”2″ : this basically tells the compiler that the TextBlock should span across 2 columns. The Grid rows and columns start with 0, and you don’t have to mention the row and column numbers for the first element. By Default, if no row or column number is mentioned, it is taken to be 0. From then onwards, we mention the numbers like this: Grid.Row=”1″ and Grid.Column=”1″. The Grid.Columspan, Grid.Column and Grid.Row are all attached properties declared by Grid (We learnt about attached properties in the previous lesson).

So we place the combobox for colour selection in Row 1, and the ListBox in Row 2 (default Column 0). We then place the TextBlock that renders the output in Column 1 and Row 1, and the TextBox that accepts input in Column 1 and Row 2. The actual code remains the same. So, the overall, output will now look like this:

WPF5_1

If you want to be able to resize the grid rows or columns, or separate them more clearly, you can use a “GridSplitter” but remember that you need to consider it as a separate element and place it between the rows or columns that you want to be able to resize with something like this:

<GridSplitter Grid.Row=”0″ Grid.RowSpan=”2″ Grid.Column=”1″ Width=”8″ Background=”Black” ResizeBehavior=”PreviousAndNext” ResizeDirection=”Columns” />

The ResizeDirection tells what the splitter will resize (row or column) and ResizeBehaviour tells which rows or columns will get resized. In the above code, the splitter is placed in its own space, and the previous and next columns are set to be resized.

Leaving the GridSplitter aside, as you can see, in the above example, the output looks more or less the same as it did with the DockPanel. In fact, many controls like Grid, StackPanel and DockPanel can be used interchangeably in most scenarios. However, there are certain scenarios where their behaviour is different. For instance, the order of child element can affect their size in DockPanel because within DockPanel they are docked in available space, unlike StackPanel in which all elements have equal footage. Look at the below example from MSDN site:

IC101120

In the above image, the first row uses a DockPanel and second row uses a StackPanel. You can see the difference in rendering obviously.

Ok, now let us try to enhance this application further using a StackPanel. What we are going to do is to try and display the output text in different font sizes using a StackPanel. So, we will replace the output TextBlock with 4 TextBlocks stacked one above the other, in a StackPanel like this:

<StackPanel Grid.Column=”1″ Grid.Row=”2″>
<TextBlock Text=”{Binding ElementName=mytextbox, Path=Text}” TextWrapping=”Wrap”
FontFamily=”{Binding ElementName=mylistbox, Path=SelectedItem}”
Foreground=”{Binding ElementName=mycombo, Path=SelectedItem.Content}”
FontSize=”10″></TextBlock>
<TextBlock Text=”{Binding ElementName=mytextbox, Path=Text}” TextWrapping=”Wrap”
FontFamily=”{Binding ElementName=mylistbox, Path=SelectedItem}”
Foreground=”{Binding ElementName=mycombo, Path=SelectedItem.Content}”
FontSize=”12″></TextBlock>
<TextBlock Text=”{Binding ElementName=mytextbox, Path=Text}” TextWrapping=”Wrap”
FontFamily=”{Binding ElementName=mylistbox, Path=SelectedItem}”
Foreground=”{Binding ElementName=mycombo, Path=SelectedItem.Content}”
FontSize=”14″></TextBlock>
<TextBlock Text=”{Binding ElementName=mytextbox, Path=Text}” TextWrapping=”Wrap”
FontFamily=”{Binding ElementName=mylistbox, Path=SelectedItem}”
Foreground=”{Binding ElementName=mycombo, Path=SelectedItem.Content}”
FontSize=”16″></TextBlock>
</StackPanel>

As you can see, we have defined the row and column numbers for the StackPanel and not for individual elements within it. The StackPanel will sit on Row 1 in Column 1 and the child elements (TextBlocks) will be stacked inside it one above the other. The text of each of the TextBlocks is bound to the Text in the input Textbox such that when we change the input the Text of these blocks will also change. We have used TextWrapping=”Wrap” so that if the text is too long, it is rendered on the next line. The colour is bound to the selected item in the combobox so that then the user selects a different color, the output is rendered accordingly. All this is same as the previous FontViewer application However, the font size of each TextBlock is different so that the text is now rendered in different sizes as shown here:

WPF5_2

It is possible to bind the FontSize to a combobox too so that the size is not static (as above) but changes according to user preference, same way as color changes. You can also make the output text render in different sizes next to each other (instead of one below the other) by changing the StackPanel’s Orientation=”Horizontal”. When you combine the properties of the panels with the properties of its child elements (such as Margin, HorizontalAlignment, VerticalAlignment etc), the possibilities are virtually unlimited, and as you can see, we have hardly even written any code. That is the beauty of WPF although for more complex scenarios, you will have to write code.

In the definitions for different panels, we already discussed that StackPanel and WrapPanel are very similar. This basically means that they can be used interchangeably. However, we also discussed that WrapPanel wraps the elements into next line if space is not sufficient. We can see this by substituting StackPanel with WrapPanel in the above example. First, let us change the orientation of StackPanel to “Horizontal”. Then, when we resize the window to compress it, this is what we see:

WPF5_3

See how the TextBlock contents (“Type here” in different font sizes) that are inside the StackPanel are cut off? On the other hand, if we replace StackPanel with WrapPanel in the code and make no other changes, this is what we see when we run the application and do the resizing:

WPF5_4

See how the WrapPanel put the TextBlock contents into the next line? There are situations when this behaviour can be useful.

So hopefully now you have a basic idea about how to use the dockpanel, grid, stackpanel and wrappanel. We are not going to tackle the use of Canvas or TabPanel right now. The Canvas control limits the dynamic layout capabilities of WPF to a large extent due to its rigid size and positioning requirements and it is best avoided unless absolutely necessary. Basically the Canvas is more suitable for layout of drawings and not for controls. We are going to tackle TabPanel when we learn more about the TabControl. As we proceed further with complicated application layouts, you will also learn about other advanced controls. For now, these four most commonly used controls will serve you well in most scenarios.

Leave a Reply

Your email address will not be published. Required fields are marked *


9 × = eighteen

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>