Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll ListViewItem to be at the top of a ListView

In WPF, I know I can use ListView.ScrollIntoView to scroll a particular item into view, but it will always do the least amount of scrolling so that the item is shown.

How can I make it scroll so that the item I want to show is scrolled to the top of the ListView?

I've thought about calling ScrollIntoView twice, once for the item I want at the top, and once for the last shown item, but I don't know how to find out what the last shown item.

like image 695
Ray Avatar asked Jul 03 '09 00:07

Ray


People also ask

How do I scroll to a specific position in ListView flutter?

To scroll a Flutter ListView widget horizontally, set scrollDirection property of the ListView widget to Axis. horizontal. This arranges the items side by side horzontally.

Is there a way to automatically scroll to an element in ListView builder?

You can assign a GlobalKey to the item you want to scroll to and make use of ScrollPosition.

How can list box be made to scroll smoothly?

Scrolling behavior in a ListBox is provided by a ScrollViewer. By default, the CanContentScroll property of the containing ScrollViewer is set to true, indicating that the items panel (e.g. a StackPanel) is responsible for the scrolling. The StackPanel scrolls one item at a time as you drag the scrollbar thumb.

What is widget we use in the Talk to scroll to specific position in list?

What is widget we use in the Talk to scroll to specific position in list? A scroll controller creates a [ScrollPosition] to manage the state-specific to an individual [Scrollable] widget.


2 Answers

This is an alternative to the answer of @rmoore that avoids scrolling to the bottom. Also note that this is only usefull in cases where SelectionMode=Single.

In case that ScrollViewer.CanContentScroll=True the ScrollViewer can scroll directly to the SelectedIndex.

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;      
    scrollViewer.ScrollToVerticalOffset(listView.SelectedIndex);
}

and in case ScrollViewer.CanContentScroll=False some additional XAML is required:

<ListView ScrollViewer.CanContentScroll="False" ItemsSource="{Binding Percents}" x:Name="uiListView">
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <EventSetter Event="Selected" Handler="OnSelected"/>
        </Style>
     </ListView.ItemContainerStyle>
</ListView>

And the ScrollViewer can move to the vertical offset of the top of the ListViewItem.

private void OnSelected(object sender, RoutedEventArgs e)
{
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;      

    ListViewItem listViewItem = (ListViewItem)e.Source;
    Point offset = listViewItem.TranslatePoint(new Point(), scrollViewer);
    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset.Y);
}
like image 178
Wouter Avatar answered Sep 21 '22 23:09

Wouter


We can do this by obtaining the ScrollViewer that is present in the ListView's ControlTemplate. If you have access to a ScrollViewer then there are a lot of different scrolling methods exposed.

First, we can create a ListView that we want to add this effect to:

<ListView ItemsSource="{Binding Percents}"
      SelectionChanged="OnSelectionChanged"
      x:Name="uiListView"/>


public List<int> Percents { get; set; }

public Window1()
{
    InitializeComponent();

    Percents = new List<int>();
    for (int i = 1; i <= 100; i++)
    {
        Percents.Add(i);
    }
    this.DataContext = this;
}

We will also need something that we can use to obtain the ScrollViewer from the ListView. I've used something similar to this before to work with custom scrolling, and we can use it here as well.

public static DependencyObject GetScrollViewer(DependencyObject o)
{
    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;
}

Now, we just need to handle the SelectionChanged event. Because we are trying to scroll an item to the top of the list, the best option is to scroll to the bottom, and then re-scroll up to our selected item. As you said, ScrollIntoView will scroll just until the item is visible, and so once the selected item reaches the top as it scrolls back up, it will cease leaving us with our selected item at the very top of the list.

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ScrollViewer scrollViewer = GetScrollViewer(uiListView) as ScrollViewer;
    scrollViewer.ScrollToBottom();

    uiListView.ScrollIntoView(e.AddedItems[0]);
}
like image 24
rmoore Avatar answered Sep 18 '22 23:09

rmoore