Search code examples
c#.netwpflistview

How can I programmatically scroll a WPF listview?


Is it possible to programmatically scroll a WPF listview? I know winforms doesn't do it, right?

I am talking about say scrolling 50 units up or down, etc. Not scrolling an entire item height at once.


Solution

  • You'll have to grab the ScrollViewer from the ListView and use the methods exposed by it to override the scrolling. You can also scroll by getting the main content area and using it's implementation of the IScrollInfo interface.

    Here's a little helper to get the ScrollViwer component of something like a ListBox, ListView, etc.

    public static DependencyObject GetScrollViewer(DependencyObject o)
    {
        // Return the DependencyObject if it is a ScrollViewer
        if (o is ScrollViewer)
        { return o; }
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
        {
            var child = VisualTreeHelper.GetChild(o, i);
            var result = GetScrollViewer(child);
            if (result == null)
            {
                continue;
            }
            else
            {
                return result;
            }
        }
        return null;
    }
    

    And then you can just use .LineUp() and .LineDown() like this:

    private void OnScrollUp(object sender, RoutedEventArgs e)
    {
        var scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;
        if (scrollViewer != null)
        {
            // Logical Scrolling by Item
            // scrollViewer.LineUp();
            // Physical Scrolling by Offset
            scrollViewer.ScrollToVerticalOffset(scrollViwer.VerticalOffset - 3);
        }
    }
    
    private void OnScrollDown(object sender, RoutedEventArgs e)
    {
        var scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;
        if (scrollViewer != null)
        {
            // Logical Scrolling by Item
            // scrollViewer.LineDown();
            // Physical Scrolling by Offset
            scrollViewer.ScrollToVerticalOffset(scrollViwer.VerticalOffset + 3);
        }
    }
    
    <DockPanel>
        <Button DockPanel.Dock="Top"
                Content="Scroll Up"
                Click="OnScrollUp" />
        <Button DockPanel.Dock="Bottom"
                Content="Scroll Down"
                Click="OnScrollDown" />
        <ListView x:Name="uiListView">
            <!-- Content -->
        </ListView>
    </DockPanel>
    

    The Logical scrolling exposed by LineUp and LineDown still scroll by item, if you want to scroll by a set amount you should use the ScrollToHorizontal/VerticalOffset that I've used above. If you want more complex scrolling, take a look at the answer I've provided in this other question.