locked
Horizontal Scrolling is broken in ListView

    Question

  • Horizontal Scrolling is broken. The problem appears to be in the ItemsStackPanel which provides the default panel for this control. Here's a simple chunk of code to reproduce the problem:

    <Page x:Class="App2.MainPage"
    	  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    	  mc:Ignorable="d"
    	  xmlns:local="using:App2"
    	  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    	  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
        <Page.Resources>
            <Style x:Key="TextBlock"
                   TargetType="TextBlock">
                <Setter Property="FontSize"
                        Value="24"/>
                <Setter Property="Margin"
                        Value="50, 10"/>
            </Style>
        </Page.Resources>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <ListView Background="White"
                      Height="100"
                      Width="1000"
                      ScrollViewer.HorizontalScrollBarVisibility="Visible"
                      ScrollViewer.HorizontalScrollMode="Enabled"
    				  Foreground="Black">
                <ListView.Items>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Line 1:"
                                   Foreground="Red"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column One"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Two"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Three"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Four"
                                   Style="{StaticResource TextBlock}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Line 2:"
                                   Foreground="Red"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column One"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Two"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Three"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Four"
                                   Style="{StaticResource TextBlock}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Line 1:"
                                   Foreground="Red"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column One"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Two"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Three"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Four"
                                   Style="{StaticResource TextBlock}"/>
                    </StackPanel>
                </ListView.Items>
            </ListView>
        </Grid>
    </Page>
    Unfortunately, using a WrapGrid or VirtualizingStack panel isn't an option as the StackPanel.Header properties don't want to cooperate.  I could use some ideas for a work-around.


    • Edited by DRAirey1 Tuesday, May 20, 2014 1:08 PM
    Tuesday, May 20, 2014 1:07 PM

All replies

  • Already solved this problem in WPF, but not in Windows Store.  I have a ScrollViewer with a header area. I want everything (header and content) to scroll horizontally, but I only want the content to scroll vertically (leaving the header at a fixed position at the top of the control).  I always end up with a vertical scroll bar that is off-screen to the right until it's scrolled into view horizontally, then it works as you would expect it. Here's what I have so far:

                        <ScrollViewer HorizontalScrollBarVisibility="Visible"
    								  HorizontalScrollMode="Enabled"
    								  x:Name="HeaderScrollViewer">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <controls:ColumnViewHeaderRowPresenter AllowsColumnReorder="{TemplateBinding AllowsColumnReorder}"
    																   Background="Orange"
    																   ColumnHeaderContainerStyle="{TemplateBinding ColumnHeaderContainerStyle}"
    																   ColumnHeaderHorizontalAlignment="{TemplateBinding ColumnHeaderHorizontalAlignment}"
    																   ColumnHeaderStringFormat="{TemplateBinding ColumnHeaderStringFormat}"
    																   ColumnHeaderTemplate="{TemplateBinding ColumnHeaderTemplate}"
    																   ColumnHeaderTemplateSelector="{TemplateBinding ColumnHeaderTemplateSelector}"
    																   ColumnHeaderVerticalAlignment="{TemplateBinding ColumnHeaderVerticalAlignment}"
    																   Columns="{TemplateBinding Columns}"
    																   x:Name="Header"/>
                                <ScrollViewer HorizontalAlignment="Left"
    										  BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
    										  Grid.Row="1"
    										  HorizontalScrollBarVisibility="Hidden"
                                              Height="{Binding Path=ViewportHeight, ElementName=HeaderScrollViewer}"
    										  HorizontalScrollMode="Disabled"
    										  x:Name="ContentScrollViewer"
    										  VerticalScrollBarVisibility="Visible"
    										  VerticalScrollMode="Enabled">
                                    <ItemsPresenter Footer="{TemplateBinding Footer}"
    												FooterTemplate="{TemplateBinding FooterTemplate}"
    												FooterTransitions="{TemplateBinding FooterTransitions}"
    												Header="{TemplateBinding Header}"
    												HeaderTemplate="{TemplateBinding HeaderTemplate}"
    												HeaderTransitions="{TemplateBinding HeaderTransitions}"
    												Padding="{TemplateBinding Padding}"/>
                                </ScrollViewer>
                            </Grid>
                        </ScrollViewer>
                    </ControlTemplate>
    


    Donald Roy Airey

    Tuesday, May 20, 2014 12:30 AM
  • Hi,

    In windows 8.1, ScollViewer have a new ScrollViewer.TopHeader propertywhich can gets or sets the content of the top header. And the top header scrolls horizontally, but not vertically.

    <ScrollViewer Width="300" Height="300" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible"  >
                <ScrollViewer.TopHeader>
                    <TextBlock Text="header"></TextBlock>
                </ScrollViewer.TopHeader>
    
                <Image Source="Assets/Capture.PNG" HorizontalAlignment="Left" VerticalAlignment="Top" ></Image>
            </ScrollViewer>

    Note The LeftHeader, TopHeader, and TopLeftHeader properties can be set only when ScrollViewer content's HorizontalAlignment is Left and VerticalAlignment is Top.

    Best Wishes!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey. Thanks<br/> MSDN Community Support<br/> <br/> Please remember to &quot;Mark as Answer&quot; the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Tuesday, May 20, 2014 3:01 AM
  • Annie,

    Great suggestion except that the ItemStackPanel is broken and the ScrollViewer with a Header won't let me use a WrapGrid (which seems to work pretty well for horizontal scrolling).  Please take your example above and add three or four columns to it until it exceeds the width of 300 that you assigned to the ScrollViewer.  Let me know what you find.


    Donald Roy Airey


    Tuesday, May 20, 2014 12:03 PM
  • A list control doesn't care how the items are presented, and actually uses underlying containers to help organize the list items - so setting scroll information like you're attempting may not always work.

    To get the items to be presented in a horizontal manner, you'll have to provide an items panel template.  The items will then be placed into  that control, and the items panel controls item layout.  The parent list control actually doesn't care how the items are organized.

    I'd attack the problem like this:

    <ListView> 
       <ListView.ItemsPanel>
         <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
         </ItemsPanelTemplate>
       </ListView.ItemsPanel>
    </ListView>
    Although not for the Windows Store apps exactly, Dr WPF has some great tutorials on containers - you should check them out, the XAML principles still apply.  Go through the whole A-Z...

    Darin R.

    Tuesday, May 20, 2014 2:55 PM
  • Thanks for the suggestion, but I already know the problem is with the panel.  The default panel, ItemStackPanel, is broken, which is the gist of my original post.  The StackPanel does not virtualize, so performance is going to be terrible.  The other options, WrapGrid and VirtualizingStackPanel throw an error when I try to use a fixed header on the control (All I really want to do is create a simple DataGrid with headers).

    Any other angles on the problem would be welcome.


    Donald Roy Airey

    Tuesday, May 20, 2014 3:07 PM
  • What is the error you're getting trying to create fixed headers with VirtualizingStackPanel?


    Darin R.

    Tuesday, May 20, 2014 3:24 PM
  • On second though, I don't really have enough information about what you're trying to do, or why you think the panel/scrolling is broken.

    Can you post a complete sample project, and also indicate exactly what is wrong with scrolling in that sample?   That'd be better than going through a ton of questions one at a time...


    Darin R.

    Tuesday, May 20, 2014 3:31 PM
  • I'm open to suggestions: how do you propose I post a 'complete' example.  Do you have some sort of FTP facility where I can drop a zip file?  If not, just open up Visual Studio, create a blank "Windows Store" project and paste the page in the OP into the default main page.  When you run it, you'll notice that you can't scroll horizontally.

    Donald Roy Airey

    Tuesday, May 20, 2014 3:37 PM
  • Toss the app on OneDrive, share a link here.

    But, here's the problem that I can see:

    First, you have a collection of StackPanels as content.  You're assuming that the content presentor can reflect somehow into the content and pull out a width magically from "any-old-object":  It can't, because those "objects" can be anything - a string, a c# object - anything.

    The XAML engine eventually knows how to draw the object only because there are built in template converters in XAML that know how to draw certain items.  Yes, the converters know how to draw content, but aren't called initially for any measuring of any kind.

    So the content presenter just happily draws the object using the template xml with a width 100% of the listbox/view - therefore no scrolling is needed, ever.

    To fix the problem, give the content a width, or specify to the listbox how big the content is (bold items are mods)

     <ListView Background="White"
                      Height="100"
    				  Foreground="Black" Margin="717,334,241,334"
                      ScrollViewer.HorizontalScrollMode="Enabled"
                      ScrollViewer.HorizontalScrollBarVisibility="Visible">
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel />
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding }" Width="500"/>
                    </DataTemplate>
                </ListView.ItemTemplate>
                <ListView.Items>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Line 1:"
                                   Foreground="Red"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column One"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Two"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Three"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Four"
                                   Style="{StaticResource TextBlock}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Line 2:"
                                   Foreground="Red"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column One"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Two"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Three"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Four"
                                   Style="{StaticResource TextBlock}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Line 1:"
                                   Foreground="Red"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column One"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Two"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Three"
                                   Style="{StaticResource TextBlock}"/>
                        <TextBlock Text="Column Four"
                                   Style="{StaticResource TextBlock}"/>
                    </StackPanel>
                </ListView.Items>
    Does that make sense?


    Darin R.

    Tuesday, May 20, 2014 3:53 PM
  • Darin,

    No, I'm afraid what you said doesn't make a lick of sense.  ItemsControls only convert POCOs, they don't convert UIElements, but will wrap them in a default container, such as the ListViewItem where these StackPanels will become the content of the container.  The engine has no trouble at all calculating the size of a ListViewItem with a StackPanel as the content.


    Donald Roy Airey

    Tuesday, May 20, 2014 4:14 PM
  • Sorry I couldn't help you out. 

    Try my sample, see what you think.


    Darin R.

    Tuesday, May 20, 2014 4:36 PM
  • Darin,

    Your example works just fine without the fixed width for the DataTemplate.  I agree that the VirtualizingStackPanel and WrapGrid will correctly generate the viewport width needed by the ScrollViewer.    The main problem is that the default panel - ItemStackPanel - is badly broken.  The next biggest problem is that when I use either the VirtualizingStackPanel or WrapGrid to work around the problem, then the ScrollViewer.TopHeader complains that I can only use a ItemStackPanel.

    "The TopLeftHeader, TopHeader and LeftHeader properties cannot be used when the Content is an OrientedVirtualizingPanel,  VirtualizingStackPanel, CarouselPanel or WrapGrid instance."

    Here's the code to duplicate the error:

    <Page x:Class="App2.MainPage"
    	  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    	  mc:Ignorable="d"
    	  xmlns:local="using:App2"
    	  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    	  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
        <Page.Resources>
            <Style x:Key="TextBlock"
    			   TargetType="TextBlock">
                <Setter Property="FontSize"
    					Value="24"/>
                <Setter Property="Margin"
    					Value="50, 10"/>
            </Style>
            <!-- Default style for Windows.UI.Xaml.Controls.ListView -->
            <Style TargetType="ListView">
                <Setter Property="IsTabStop"
    					Value="False"/>
                <Setter Property="IsTabStop"
    					Value="False"/>
                <Setter Property="TabNavigation"
    					Value="Once"/>
                <Setter Property="IsSwipeEnabled"
    					Value="True"/>
                <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
    					Value="Disabled"/>
                <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
    					Value="Auto"/>
                <Setter Property="ScrollViewer.HorizontalScrollMode"
    					Value="Disabled"/>
                <Setter Property="ScrollViewer.IsHorizontalRailEnabled"
    					Value="False"/>
                <Setter Property="ScrollViewer.VerticalScrollMode"
    					Value="Enabled"/>
                <Setter Property="ScrollViewer.IsVerticalRailEnabled"
    					Value="False"/>
                <Setter Property="ScrollViewer.ZoomMode"
    					Value="Disabled"/>
                <Setter Property="ScrollViewer.IsDeferredScrollingEnabled"
    					Value="False"/>
                <Setter Property="ScrollViewer.BringIntoViewOnFocusChange"
    					Value="True"/>
                <Setter Property="ItemsPanel">
                    <Setter.Value>
                        <ItemsPanelTemplate>
                            <ItemsStackPanel Orientation="Vertical"/>
                        </ItemsPanelTemplate>
                    </Setter.Value>
                </Setter>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListView">
                            <Border Background="{TemplateBinding Background}"
    								BorderBrush="{TemplateBinding BorderBrush}"
    								BorderThickness="{TemplateBinding BorderThickness}">
                                <ScrollViewer AutomationProperties.AccessibilityView="Raw"
    										  BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
    										  HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
    										  HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
    										  IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
    										  IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
    										  IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
    										  IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
    										  IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
    										  x:Name="ScrollViewer"
    										  TabNavigation="{TemplateBinding TabNavigation}"
    										  VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
    										  VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
    										  ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
                                    <ScrollViewer.TopHeader>
                                        <TextBlock Text="This is a header that doesn't scroll"/>
                                    </ScrollViewer.TopHeader>
                                    <ItemsPresenter Footer="{TemplateBinding Footer}"
                                                    HorizontalAlignment="Left"
                                                    VerticalAlignment="Top"
    												FooterTemplate="{TemplateBinding FooterTemplate}"
    												FooterTransitions="{TemplateBinding FooterTransitions}"
    												Header="{TemplateBinding Header}"
    												HeaderTemplate="{TemplateBinding HeaderTemplate}"
    												HeaderTransitions="{TemplateBinding HeaderTransitions}"
    												Padding="{TemplateBinding Padding}"/>
                                </ScrollViewer>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Page.Resources>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <ListView Background="White"
    				  Foreground="Black"
    				  Height="100"
    				  Margin="717,334,241,334"
    				  ScrollViewer.HorizontalScrollBarVisibility="Visible"
    				  ScrollViewer.HorizontalScrollMode="Enabled">
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapGrid/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                <ListView.Items>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Foreground="Red"
    							   Style="{StaticResource TextBlock}"
    							   Text="Line 1:"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column One"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Two"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Three"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Four"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Foreground="Red"
    							   Style="{StaticResource TextBlock}"
    							   Text="Line 2:"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column One"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Two"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Three"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Four"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Foreground="Red"
    							   Style="{StaticResource TextBlock}"
    							   Text="Line 1:"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column One"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Two"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Three"/>
                        <TextBlock Style="{StaticResource TextBlock}"
    							   Text="Column Four"/>
                    </StackPanel>
                </ListView.Items>
            </ListView>
        </Grid>
    </Page>


    Donald Roy Airey

    Tuesday, May 20, 2014 5:14 PM
  • Hi,

    I was able to replicate the problem you mentioned. Let me check more information this.

    -Sagar

    Wednesday, May 28, 2014 6:18 PM
  • Hello,

    Thanks for reporting this issue. For getting around, I think using a VirtualizingStackPanel for ListView and any non-virtualizing panel for ScrollViewer can be an option.

    -Sagar

    Thursday, June 19, 2014 10:08 AM
  • Sagar,

    Yes, it is an option.  I basically had to roll my own scroll viewer.  It was a three day effort to get it all working properly (four if you count the day it took me to figure out that the ItemStackPanel was broken).  It would be much better to have this built into the framework.  I suspect I'm not the only developer in the world who needs a non-scrolling header above a scrollable region.

    Thursday, June 19, 2014 11:02 AM