StackPanel, DockPanel and scrolling items

I spent a little bit of time with this the other day, and I thought I'd pass the learnings on, in hopes it helps someone.

This is the layout what I was trying to accomplish with WPF. In a section of my window, I wanted a bit of text at the top, and then the rest filled with items. The items in this case were bits of XML with an item template that created a nice representation, but for this post we'll just use buttons, which have the same effect.

My initial XAML looked like this. You can try pasting these into XAMLPad to follow along (and add more buttons or resize the window so all buttons won't fit in the view).

<Grid xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel>
 <ItemsControl>
  <Button>Button</Button>
  <Button>Button</Button>
  <Button>Button</Button>
  <!-- ... -->
 </ItemsControl>
</StackPanel>
</Grid>

This is all well and good, but some of the Buttons are just clipped from the window and you can't get to them. This is because the ItemsControl doesn't have the built-in ability to scroll its contents, so I decided to go ahead an add a wrapping ScrollViewer.

<Grid xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel>
 <ScrollViewer>
  <ItemsControl>
   <Button>Button</Button>
   <Button>Button</Button>
   <Button>Button</Button>
   <!-- ... -->
  </ItemsControl>
 </ScrollViewer>
</StackPanel>
</Grid>

This produces a very confusing situation, in which the scroll viewer is present, but the scroll bar is disabled and goes off the window.

After looking at this for a while, I realized that the problem is that the StackPanel doesn't constrain the size of its children. So if the scroll viewer wants to be huge so it doesn't have to, the StackPanel will arrange it so, even if it clips.

The solution then was to switch to something that did constrain its children. In particular, a DockPanel is great, as it will size the last child to occupy all remaining space.

<Grid xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
<DockPanel>
 <ScrollViewer>
  <ItemsControl>
  <Button>Button</Button>
  <Button>Button</Button>
  <Button>Button</Button>
  <!-- ... -->
  </ItemsControl>
 </ScrollViewer>
</DockPanel>
</Grid>

Now I have a scroll viewer with an enabled scroll bar, which allows me to get to all the buttons.

Enjoy!