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!
Comments
Anonymous
June 09, 2009
Good to know. Thanks for sharing.Anonymous
June 09, 2009
If you suppress the stackPanel (or the DockPanel), all is working fine with just the ScrollViewer. So why adding these containers since they are not useful ? I certainly missed something :-)Anonymous
June 10, 2009
Good point, odahan. :) The original scenario was more complicated though - this was just a small markup of what I was trying to do. If you use XAMLPad a lot, one thing to note is that the 'preview' section is embedded in a larger layout context, so results may very if you take the markup and just make it the top-level thing in a Window. Haven't actually tried this to see if it applies in this case though, but again it was just for 'educational purposes'. Thanks for the clarification!Anonymous
June 11, 2009
Ok, thanks Marcelo. Perhaps the testing context has been to much simplified to see really what problem the DockPanel is solving in your sample. But it's nice to see how all these containers are playing together. WPF layout can be sometimes a bit confusing. (I use very few the xamlpad, I prefer Kaxaml, but i tested your code with xamlpad to be in the same test condition. I tried also using Kaxaml, resulting layout is identical).Anonymous
June 11, 2009
Thank you for submitting this cool story - Trackback from DotNetShoutoutAnonymous
June 13, 2009
I ran into the same problem and started on a custom panel: http://www.codeproject.com/KB/WPF/const_panel.aspx I could have used a Grid instead, but I wanted an easy stack-like interface.Anonymous
June 13, 2009
@odahan - Kaxaml is pretty cool, but I tend to rely on XamlPad out of inertia - it's there with the SDK, which will typically be on any dev machine around here. @Torbjorn - nice customer panel. I always feel that while some of the layout behaviors one might get are a bit obscure, doing custom layout that plays nice with the rest of the architecture tends to show up as a pretty elegant solution. Good stuff!