Похоже, что универсальность WPF ListView
не позволяет классу предоставить свойство типа WinForms TopItem
. Однако, если экземпляр настроен с VirtualizingStackPanel
, вы все равно можете напрямую запросить верхний индекс. Это позволяет избежать поиска и итерации, требуемой другими подходами. (Подход основан на этом посте .)
Я думаю, что метод проверки попадания, используемый в принятом ответе, является более общим, но если вам действительно нужен индекс списка, а не элемент списка, то это может сохранить вызов IndexOf
.
Моему приложению нужно было сохранять и восстанавливать позицию списка после внесения существенных изменений в содержимое списка. Код для установки верхней позиции (на основе этого поста ) также показан ниже. Для удобства они реализованы как методы расширения.
public static class ListViewExtensions {
public static int GetTopItemIndex(this ListView lv) {
if (lv.Items.Count == 0) {
return -1;
}
VirtualizingStackPanel vsp = lv.GetVisualChild<VirtualizingStackPanel>();
if (vsp == null) {
return -1;
}
return (int) vsp.VerticalOffset;
}
public static void ScrollToTopItem(this ListView lv, object item) {
ScrollViewer sv = lv.GetVisualChild<ScrollViewer>();
sv.ScrollToBottom();
lv.ScrollIntoView(item);
}
}
Чрезвычайно удобный GetVisualChild
метод взят из MSDN post :
public static class VisualHelper {
public static T GetVisualChild<T>(this Visual referenceVisual) where T : Visual {
Visual child = null;
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++) {
child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
if (child != null && child is T) {
break;
} else if (child != null) {
child = GetVisualChild<T>(child);
if (child != null && child is T) {
break;
}
}
}
return child as T;
}
}
Примечание по использованию ScrollToTopItem
: вызов ScrollToBottom()
вступает в силу немедленно, но ScrollIntoView()
кажется отложенным. Поэтому, если вы позвоните GetTopItemIndex()
сразу после ScrollToTopItem()
, вы получите индекс для элемента рядом с нижним.