Tag Archives: StackPanel

WPF layouts – StackPanel

In the post on Styles in WPF, we built the interface to a calculator by defining some controls (mostly Buttons) and then applied some predefined styles to various subsets of these controls.

In building the window and its contents we made use of several of WPF’s layouts (the Grid and DockPanel, to be precise). At the time we relied on intuition to figure out how these layouts worked; here we will delve a bit more deeply into layouts.

In WPF, all controls must be contained within one of the layout panels (either one provided by the WPF library, or one you create yourself). When you open a new project in Expression Blend (EB), you will note that the Window at the base of the project contains a layout called LayoutRoot. If you look at the XAML code generated by EB, you see that LayoutRoot is a Grid:

	Width="640" Height="480">

	<Grid x:Name="LayoutRoot"/>

In fact, Window itself is a container, and you can add one control directly to it, although if this control isn’t a layout panel like Grid, you can’t do a lot with it. For example, try deleting LayoutRoot and then adding a Button directly to the Window. By setting this Button’s properties you can make it appear in all the guises a Button can adopt, but you can’t add any more controls to the Window, so your interface is pretty limited.

Although the Grid is the most versatile layout, you can use any layout you like as the root layout in a Window. The easiest way to change the layout is by right-clicking on LayoutRoot in Objects and Timeline and choosing a layout from the “Change Layout Type” popup menu. In this post, we’ll have a look at StackPanel, so select StackPanel for LayoutRoot. You’ll see the XAML change, and also the available Properties will change.

To get an idea of what StackPanel can do, try adding a few controls (Buttons and TextBlocks should do) to LayoutRoot. You’ll see that each new control gets loaded below the previous one, in a vertical stack. StackPanel is thus a fairly simply layout in which you have a single column into which all your controls can be placed.

However, because panels can be nested, the controls you place into a StackPanel can be other layouts, so the possibilities are greater than just a single vertical stack. Before we get into that, though, there’s one annoying little ‘feature’ that we need to clear up.

If you’ve entered enough controls into LayoutRoot, you’ll see that they disappear off the bottom of the window. If you run the program and resize the window, you can make the controls vanish off the bottom for pretty well any number of controls. We would therefore like to know how we can make a scrollbar appear in such cases.

Select LayoutRoot and expand its Layout panel in Properties. You’ll see several properties that mention scrolling. If you try setting these to various values, you’ll discover that they have no (apparent) effect. No matter what you try, no scrollbar appears.

The resolution to this problem is that if you want a scrollbar to appear around any control, you need to embed this control in a ScrollViewer. In Objects and Timeline, add a ScrollViewer as the parent of LayoutRoot. Look at the ScrollViewer’s Layout properties and you’ll see the same options for scrolling here. Now try setting some options here, and this time you should see some results. In particular, experiment with the VerticalScrollBarVisibility by setting it to Auto. Now if you run the program and resize the window to hide some of the controls, a vertical scrollbar will appear. However, you’ll notice that this scrollbar hides parts of the control, as it overlays onto LayoutRoot underneath it. Enabling the horizontal scrollbar will provide both scrollbars when this happens.

The XAML at this point should look something like this:

	<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
		<StackPanel x:Name="LayoutRoot" HorizontalAlignment="Left" VerticalAlignment="Top">
			<Button Content="Button1"/>
			<Button Content="Button2"/>
			<TextBlock TextWrapping="Wrap" Text="TextBlock1"/>
			<TextBlock TextWrapping="Wrap" Text="TextBlock2"/>

So why does StackPanel have scrolling properties if they don’t do anything? Basically it’s bad class design; StackPanel implements an interface that requires these properties to be exposed publicly, so they are, even though they have no effect. Since scrollbars are used so frequently, it’s worth knowing about this early on.

Anyway, back to StackPanel. The XAML above produces this interface (when the window is large enough not to need scrollbars):

The controls’ default layout is ‘Stretch’ so they fill the width of the StackPanel. The TextBlocks may look like they are left-aligned, but the TextBlock control itself does stretch to fill the entire width; it is merely the text within the TextBlock that is left-aligned.

We can alter these alignments using the Properties panel as usual. Select Button1, for example, and change its HorizontalAlignment property to ‘Center’. Button1 will now size itself to fit around its content, and it will be centred within the StackPanel.

For the TextBlock, you can do the same thing, and the TextBlock control will size itself to fit its text, and centre itself. Note though that if you leave the TextBlock’s HorizontalAlignment at Stretch and change the alignment of its text (you can do this in the Text panel in Properties; click on the Paragraph tab and then change the TextAlignment from the combo box) , the text appears centred, but the TextBlock control itself still stretches to fill the width of the StackPanel.

If you have a lot of controls, it would be better to define a Style (as in our previous post) rather than setting all these properties for each control.

As an experiment, set the HorizontalAlignment for all four controls to ‘Center’ (so the controls size themselves to fit their content and don’t cover the whole width of the StackPanel). When you run the program and resize the window vertically so that the lower controls get hidden, what scrollbars will you see? You might think you’ll see only the vertical scrollbar, since now the controls all fit within the window, even with the vertical scrollbar showing. However, you still see both scrollbars. Why? Because the vertical scrollbar hides part of the StackPanel, and it is that StackPanel that is embedded within the ScrollViewer.

A ScrollPanel can also stack things horizontally: just select Horizontal from its Layout property panel. If the StackPanel’s width and height are set to Auto, it will size itself to fit the controls it contains, and if it is embedded within a ScrollViewer, it will display scrollbars as appropriate.

That’s about all you can do with a StackPanel, although as mentioned earlier, by embedding other layouts as elements within a StackPanel, more complex layouts can be obtained.