Windows 10 ScrollIntoView () не прокручивает элементы в середине списка

У меня есть Listview с 20 элементами в нем. Я хочу прокручивать Listview программно.

ListView?.ScrollIntoView(ListView.Items[0]) 

прокрутит список до первого элемента.

 ListView?.ScrollIntoView(ListView.Items.Count - 1) 

прокрутит список в нижней части страницы.

Тем не менее, я не могу использовать одну и ту же функцию для прокрутки списка к элементу посередине.

 Eg: ListView?.ScrollIntoView(ListView.Items[5]) 

должен прокрутить и перенести меня в пятый элемент списка. Но вместо этого он ведет меня к первому пункту списка.

Было бы здорово, если это поведение может быть достигнуто с помощью некоторого обходного пути?

Я думаю, что вы ищете метод, чтобы прокрутить элемент вверху ListView .

В этом сообщении я создал метод расширения, который прокручивается к определенному элементу в ScrollViewer .

Идея в вашем случае такая же.

Вам нужно сначала найти экземпляр ScrollViewer в вашем ListView , а затем фактический элемент для прокрутки до, то есть ListViewItem .

Ниже приведен метод расширения для получения ScrollViewer .

 public static ScrollViewer GetScrollViewer(this DependencyObject element) { if (element is ScrollViewer) { return (ScrollViewer)element; } for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = VisualTreeHelper.GetChild(element, i); var result = GetScrollViewer(child); if (result == null) { continue; } else { return result; } } return null; } 

Как только я получу экземпляр ScrollViewer , я создал еще два метода расширения для прокрутки к элементу на основе его индекса или прикрепленного объекта соответственно. Поскольку ListView и GridView используют один и тот же базовый class ListViewBase . Эти два метода расширения также должны работать для GridView .

Обновить

В основном, методы сначала найдут элемент, если он уже отображен, затем прокрутите его прямо сейчас. Если элемент имеет значение null , это означает, что виртуализация включена, и элемент еще не реализован. Итак, чтобы сначала реализовать элемент, вызовите ScrollIntoViewAsync (метод на основе задач, чтобы обернуть встроенный ScrollIntoView , такой же, как ChangeViewAsync , который предлагает гораздо более чистый код), вычислить позицию и сохранить ее. Поскольку теперь я знаю позицию для прокрутки, мне нужно сначала прокрутить элемент до последней позиции (т.е. без анимации), а затем, наконец, прокрутить до нужной позиции с анимацией.

 public async static Task ScrollToIndex(this ListViewBase listViewBase, int index) { bool isVirtualizing = default(bool); double previousHorizontalOffset = default(double), previousVerticalOffset = default(double); // get the ScrollViewer withtin the ListView/GridView var scrollViewer = listViewBase.GetScrollViewer(); // get the SelectorItem to scroll to var selectorItem = listViewBase.ContainerFromIndex(index) as SelectorItem; // when it's null, means virtualization is on and the item hasn't been realized yet if (selectorItem == null) { isVirtualizing = true; previousHorizontalOffset = scrollViewer.HorizontalOffset; previousVerticalOffset = scrollViewer.VerticalOffset; // call task-based ScrollIntoViewAsync to realize the item await listViewBase.ScrollIntoViewAsync(listViewBase.Items[index]); // this time the item shouldn't be null again selectorItem = (SelectorItem)listViewBase.ContainerFromIndex(index); } // calculate the position object in order to know how much to scroll to var transform = selectorItem.TransformToVisual((UIElement)scrollViewer.Content); var position = transform.TransformPoint(new Point(0, 0)); // when virtualized, scroll back to previous position without animation if (isVirtualizing) { await scrollViewer.ChangeViewAsync(previousHorizontalOffset, previousVerticalOffset, true); } // scroll to desired position with animation! scrollViewer.ChangeView(position.X, position.Y, null); } public async static Task ScrollToItem(this ListViewBase listViewBase, object item) { bool isVirtualizing = default(bool); double previousHorizontalOffset = default(double), previousVerticalOffset = default(double); // get the ScrollViewer withtin the ListView/GridView var scrollViewer = listViewBase.GetScrollViewer(); // get the SelectorItem to scroll to var selectorItem = listViewBase.ContainerFromItem(item) as SelectorItem; // when it's null, means virtualization is on and the item hasn't been realized yet if (selectorItem == null) { isVirtualizing = true; previousHorizontalOffset = scrollViewer.HorizontalOffset; previousVerticalOffset = scrollViewer.VerticalOffset; // call task-based ScrollIntoViewAsync to realize the item await listViewBase.ScrollIntoViewAsync(item); // this time the item shouldn't be null again selectorItem = (SelectorItem)listViewBase.ContainerFromItem(item); } // calculate the position object in order to know how much to scroll to var transform = selectorItem.TransformToVisual((UIElement)scrollViewer.Content); var position = transform.TransformPoint(new Point(0, 0)); // when virtualized, scroll back to previous position without animation if (isVirtualizing) { await scrollViewer.ChangeViewAsync(previousHorizontalOffset, previousVerticalOffset, true); } // scroll to desired position with animation! scrollViewer.ChangeView(position.X, position.Y, null); } public static async Task ScrollIntoViewAsync(this ListViewBase listViewBase, object item) { var tcs = new TaskCompletionSource(); var scrollViewer = listViewBase.GetScrollViewer(); EventHandler viewChanged = (s, e) => tcs.TrySetResult(null); try { scrollViewer.ViewChanged += viewChanged; listViewBase.ScrollIntoView(item, ScrollIntoViewAlignment.Leading); await tcs.Task; } finally { scrollViewer.ViewChanged -= viewChanged; } } public static async Task ChangeViewAsync(this ScrollViewer scrollViewer, double? horizontalOffset, double? verticalOffset, bool disableAnimation) { var tcs = new TaskCompletionSource(); EventHandler viewChanged = (s, e) => tcs.TrySetResult(null); try { scrollViewer.ViewChanged += viewChanged; scrollViewer.ChangeView(horizontalOffset, verticalOffset, null, disableAnimation); await tcs.Task; } finally { scrollViewer.ViewChanged -= viewChanged; } } 

Более простой подход, но без анимации

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

 MyListView?.ScrollIntoView(MyListView.Items[5], ScrollIntoViewAlignment.Leading); 

ScrollIntoView просто приносит элемент в представление, период, он не прокручивается до строки.

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

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

Если вы вызываете его на члене, и он в настоящее время виден, он вообще не выполняет никаких операций.

Я решаю это как:

  var sv = new ScrollViewerHelper().GetScrollViewer(listView); sv.UpdateLayout(); sv.ChangeView(0, sv.ExtentHeight, null); 

И метод GetScrollViewer:

 public ScrollViewer GetScrollViewer(DependencyObject element) { if (element is ScrollViewer) { return (ScrollViewer)element; } for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = VisualTreeHelper.GetChild(element, i); var result = GetScrollViewer(child); if (result == null) { continue; } else { return result; } } return null; } 

кредиты владельцу кода

  • WPF: отобразить значение bool как «Да» / «Нет»
  • Как сортировать элементы TreeView с помощью SortDescriptions в Xaml?
  • Объединить расширитель и сетку (изменяемый размер расширителя)
  • Как отключить элемент списка ListBox на основе значения свойства?
  • Как связать перечисление с элементом управления combobox в WPF?
  • Редактирование одного клика в WPF DataGrid
  • WPF Fade Animation
  • Потяните за обновлениями на Windows Phone
  • Являются ли Click, Tapped и PointerPressed синонимом в WinRT-XAML?
  • Ошибка ReSharper WPF: «Не удается разрешить символ« MyVariable »из-за неизвестного DataContext»
  • Как добавить поведение Blend в стильном сеттере
  • Interesting Posts

    Обучение VB6

    существует ли эквивалент Java, эквивалентный нулевому коалесцирующему оператору (??) в C #?

    Каков наилучший способ сделать подстроку в пакетном файле?

    JAVA – Лучший подход к анализу огромного (особо большого) файла JSON

    Какая работа была выполнена для кросс-платформенной мобильной разработки?

    Контекст данных EF – Async / Await & Multithreading

    Штрих-код на скорости 4

    Выберите несколько изображений из фотоальбома на Android с помощью намерений

    Разница между объявлением переменных до или в цикле?

    Как настроить ярлык для запуска ConEmu из Launchy с определенной задачей?

    Как показать SQL-запросы в консоли Rails?

    Разница между определением @interface в файлах .h и .m

    Нормальные формы – 2-й и 3-й – это разница только составных клавиш? нетривиальная зависимость?

    Является ли XML чувствительным к регистру?

    У общих методов в .NET не может быть указан их возвращаемый тип. Зачем?

    Давайте будем гением компьютера.