Прокрутить ListViewItem, чтобы быть в верхней части ListView

В WPF я знаю, что могу использовать ListView.ScrollIntoView для прокрутки определенного элемента в представлении, но он всегда будет делать наименьшее количество прокрутки, чтобы этот элемент отображался.

Как я могу прокрутить его, чтобы элемент, который я хочу показать, прокручивается вверху списка ListView?

Я думал о вызове ScrollIntoView дважды, один раз для элемента, который я хочу в верхней части, и один раз для последнего показанного элемента, но я не знаю, как узнать, что последний показанный элемент.

Ответ 1

Мы можем сделать это, получив ScrollViewer, который присутствует в элементе управления ListView ControlTemplate. Если у вас есть доступ к ScrollViewer, то есть много различных методов прокрутки.

Во-первых, мы можем создать ListView, который мы хотим добавить к этому эффекту:

<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;
}

Нам также понадобится что-то, что мы можем использовать для получения ScrollViewer из ListView. Я использовал что-то похожее на это раньше, чтобы работать с пользовательской прокруткой, и мы также можем использовать его здесь.

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;
}

Теперь нам просто нужно обработать событие SelectionChanged. Поскольку мы пытаемся прокрутить элемент вверху списка, лучшим вариантом является прокрутка вниз, а затем повторная прокрутка вверх до нашего выбранного элемента. Как вы сказали, ScrollIntoView будет прокручиваться до тех пор, пока элемент не будет виден, и поэтому, когда выбранный элемент достигнет вершины, когда он прокрутит резервную копию, он перестанет оставлять нас с выбранным вами элементом в самом верху списка.

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

    uiListView.ScrollIntoView(e.AddedItems[0]);
}