Как получить начальный индекс и количество видимых элементов в ListView?

У меня есть просмотр списка, работающий в виртуальном режиме, в представлении LargeIcons. Извлечения стоят дорого, поэтому я хочу запросить данные для всех видимых элементов. Как получить начальный индекс и общее количество видимых элементов?

Обновление: мне известно о событии CacheVirtualItems. Сторонней базе данных, которую мы используем, требуется ~3 секунды для извлечения одной записи, но ~4 секунды для извлечения тысячи записей, поэтому мне приходится делать их большими блоками. Мне нужно убедиться, что видимые записи находятся среди тех, которые мы извлекаем, поэтому мне нужно знать начальный индекс и общее количество видимых элементов. Если это невозможно, мне придется найти обходной путь (который, вероятно, будет включать использование DataGridView с загрузкой ячеек изображения для имитации представления LargeIcons), но я хотел бы сделать это правильно, если это возможно.

7 ответов

НАСТОЯЩИЙ ответ:
* получить ScrollViewer из ListView.
* ScrollViewer.VerticalOffset - это индекс первого показанного элемента.
* ScrollViewer.ViewportHeight - количество отображаемых элементов.

Чтобы получить ScrollViewer, вам понадобится функция FindDescendant(FrameworkElement, Type), которая будет искать в дочерних элементах ListView. Позвоните после загрузки окна.

Код в VB.Net и в C#:

Public Function FindDescendant(ByVal MyElementToSeek As FrameworkElement, _
                                  ByVal TypeToFind As Type) As FrameworkElement
    If MyElementToSeek Is Nothing Then Return Nothing
    If MyElementToSeek.GetType() = TypeToFind Then Return MyElementToSeek
    For i = 0 To VisualTreeHelper.GetChildrenCount(MyElementToSeek) - 1
        Dim OneChild = TryCast(VisualTreeHelper.GetChild(MyElementToSeek, i), FrameworkElement)
        Dim Result = FindDescendant(OneChild, TypeToFind)
        If Result IsNot Nothing Then Return Result
    Next
    Return Nothing
End Function

,

public FrameworkElement FindDescendant(FrameworkElement MyElementToSeek, 
                                         Type TypeToFind) 
{
    if (MyElementToSeek == null) return null;
    if (MyElementToSeek.GetType() == TypeToFind) return MyElementToSeek;
    for (i = 0; 
               (i<= (VisualTreeHelper.GetChildrenCount(MyElementToSeek) - 1)); i++) 
      {
        object OneChild = TryCast(VisualTreeHelper.GetChild(MyElementToSeek, i),
                                                         FrameworkElement);
        object Result = FindDescendant(OneChild, TypeToFind);
        if (Result) return Result;
        }
     return null;
    }
}

    ' MyScrollViewer = FindDescendant(MyListView, ScrollViewer)

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

Например, что-то вроде:

        for (int index = 0; index < list.Items.Count; index++)
        {
            if (list.ClientRectangle.IntersectsWith(item.GetBounds(ItemBoundsPortion.Entire)))
            {
                // Add to the list to get data.
            }
            else
            {
                // We got them all.
                break;
            }
        }

Я не уверен, какой эффект окажет на это сортировка.

Просто с головы до головы, и я не проверял это, но не могли бы вы сделать:

private void GetIndexes(ListView vv, out int startidx, out int count)
{
            ListViewItem lvi1 = vv.GetItemAt(vv.ClientRectangle.X+6, vv.ClientRectangle.Y + 6); 
            ListViewItem lvi2 = vv.GetItemAt(vv.ClientRectangle.X+6, vv.ClientRectangle.Bottom-10); 
            startidx = vv.Items.IndexOf(lvi1); 
            int endidx = vv.Items.IndexOf(lvi2);
            if (endidx == -1) endidx = vv.Items.Count;
            count = endidx - startidx;
}

Я знаю, что этот пост старый..... Неправильно

MyScrollViewer = FindDescendant(MyListView, ScrollViewer)

Право это:

Dim Myscrollviwer As ScrollViewer

Myscrollviwer = FindDescendant(myListView3, GetType(ScrollViewer))
MsgBox(Myscrollviwer.VerticalOffset)

Вы видели событие CacheVirtualItems? Элемент управления будет запрашивать диапазон элементов вместо одного за другим. То есть, если прокрутить, он все равно может попросить только по одному за раз. Но pagedown/up запустит механизм кеширования.

Попробуй это:

If ListView.Items.Count > 0 Then
    Dim lvi As ListViewItem = ListView.TopItem
    If lvi Is Nothing Then Return
    Dim startIndex As Integer = lvi.Index
    Dim lastVisible As Integer = startIndex
    While ListView.Items(lastVisible).Bounds.Bottom < Me.lvRes.Bounds.Bottom
        lastVisible += 1
    End While
    lastVisible -= 1
End If
foreach (var t in listView1.Items)
{                        

    var lvitem = listView1.ItemContainerGenerator.ContainerFromItem(t) as ListViewItem;                   
    if (lvitem == null) continue;
    //lvitem will = null if it is not visible 

    // otherwise do stuff with lvitem such as:
    lvitem.Foreground = Brushes.Green;

}
Другие вопросы по тегам