Beware ListView inside StackPanel

Aug 24, 2008 at 10:49 PM
Compositional UI designers beware! If you use the StackPanel and attempt to load a view containing any kind of ListView inside that StackPanel's tree, said ListView will never scroll vertically.

At least I can't figure a way to make it work. I've replaced the ListView's ItemsPanel and tried the equivalent with Styles. No dice. Oh, I can stick a DockPanel in there (and give up virtualizating the ListView) but now it scrolls horizontally and no amount of fiddling with DockPanel.Dock seems to make a difference.

This is a big problem for us because people use StackPanels all the time, not knowing what havoc they create for nested views.

My reading of Chris Anderson's "Essential WPF" says this problem is intractible ("StackPanel must be used carefully because it measures children using an infinite width or height based on the orientation. This lack of a control on size can break other child layout panels, specifically causing problems for .. ScrollViewer. ... There is no way to avoid this problem with StackPanel." (p.190)

Here's the scenario:

<!-- Scrolls ok -->
<DockPanel>
 <ListBox ItemsSource="{Binding}"/>
<!-- bind to lots of items -->
</DockPanel>

<!-- Won't scroll for me -->
<StackPanel>
 <ListBox ItemsSource="{Binding}"/>
<!-- bind to lots of items -->
</StackPanel>

Any suggestions?
Aug 25, 2008 at 3:47 AM
Have you tried replacing the StackPanel with a ScrollViewer?   WPF Unleashed - pg-173,174 :)   Havn't done anything with it personally - still working my way through the book.
Aug 25, 2008 at 5:51 AM
Edited Aug 25, 2008 at 5:53 AM
Let me try to clarify. I am warning against using StackPanel in any situation in which someone might introduce a ListView within that StackPanel. Imagine this structure:

 <StackPanel x:Name="Oops">
    <ContentControl x:Name="NestedRegion" 
        Width="Auto" Height="Auto" 
        HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"/>
</StackPanel>

The author of this layout view is inviting clients to add views to "NestedRegion". Unfortunately, "NestedRegion" is unconstrained and will not scroll any material placed inside of it.

To illustrate, add a simple view to "NestedRegion" such as:

<ScrollViewer>
    <ListBox ItemsSource="{Binding}"/><!-- bind to lots of items -->
</ScrollViewer>

The ScrollViewer does not help. In fact, you will see a big empty scrollbar on the right .. with no opportunity to scroll. The ListBox actually has its own ScrollViewer in its default ItemsPanelTemplate so all we are doing is doubling up on ScrollViewers .. to no avail. The author of the "Oops" view holding "NestedRegion" has handcuffed all clients.

Interestingly, if the author of "Oops" tries to compensate by rewriting his view as:

 <ScrollViewer x:Name="OopsAgain">
     <StackPanel >
       <ContentControl x:Name="NestedRegion" 
           Width="Auto" Height="Auto" 
           HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"/>
   </StackPanel>
</ScrollViewer>

.. a ScrollViewer will appear ... but now it covers the entirety of  each view added to NestedRegion. It does not help an embedded ListView scroll properly.

To make this evident, imagine we add a view to NestedRegion consisting of a DockPanel holding:

a) Label "A"
b) A ListView "B" with lots of stuff
c) Label "C".

Here's a schematic representation of the entire logical tree:

<ScrollViewer x:Name="OopsAgain">
  <StackPanel>
       <ContentControl x:Name="NestedRegion" >
            <!------ view added to "NestedRegion ----->
            <DockPanel>
                 <Label Content="A"       DockPanel.Dock="Top"/>
                 <ListView x:Name="B"  DockPanel.Dock="Top" ... />
                 <Label Content="C"       DockPanel.Dock="Top"/>
            </DockPanel >
            <!------------------------------------------->
     </ContentControl>
  </StackPanel>
</ScrollViewer>

You would see that, yes, there is scrolling of the added DockPanel .. but of the whole DockPanel. You can see Label "A" but you can't see Label "C" until you have scrolled the entire length of the ListView "B". That's not what I, the hopeful author of the added view, intend. I want to see Label "A', a scrollable ListView "B", and Label "C" ... all at the same time.

The lesson: When you write a view with a region, do not let a StackPanel appear as an ancestor of that region.

I hope I'm wrong.
Jan 8, 2009 at 12:26 PM

 

I am also facing a similar problem. Created a user control and added a stackpanel to it. Then put the user control in a region. When resizing the shell the contents of stackpanel dont bring the horizontal scroll bar or vertical scrollbar. Putting the scrollviewer doesnt help either. The scroll bars are visible but disabled. Anyone can help me, sure its a common problem

Any help?

Jan 17, 2009 at 4:25 AM
I think the only work around is to not use a StackPanel as a host for a control that may need to scroll. The control thinks it has an infinite height to work with so its CanContentScroll property is never set to true. I struggled with this for 2 days with my Treeview wondering where the scrollbars went. I replaced the StackPanel with a Grid and everything was peachy.
Jul 6, 2009 at 2:53 PM
Edited Jul 6, 2009 at 2:57 PM

Did anyone resolve this?

I have a contentcontrol and loading a different view inside the contentcontrol. This new view has a list which needs to scroll, but I seem to have similar problem with not viewing the scroll bars. Oh, and i have an expander in th efirst view too.

So

<Expander>

<Expander.Header> ... Some buttons .. </  >

<ContentControl .. RegiaonManager.RegionName= "" />

... Load the new view in this region. This new view has a list view which needs to scroll ..

</Expander>