如何获取ListView中的可见项的起始索引和数量?

时间:2008-12-16 17:21:15

标签: c# listview

我在LargeIcons视图中有一个以虚拟模式工作的listview。检索很昂贵,所以我想要求所有可见项目的数据。如何获取可见项目的起始索引和总数?

更新:我知道CacheVirtualItems事件。我们使用的第三方数据库需要大约3秒来检索单个记录,但是需要大约4秒来检索一千条记录,所以我必须在大块中执行它们。我需要确保可见记录在我们检索的记录中,因此我需要知道可见项的起始索引和总数。如果这不可行,我将不得不找到一个解决方法(这可能涉及使用带有大量图像单元的DataGridView来模仿LargeIcons视图)但是如果可能的话我想这样做。

7 个答案:

答案 0 :(得分:2)

真正的答案是:
*获取ListView的ScrollViewer * ScrollViewer.VerticalOffset是第一个显示项目的索引 * ScrollViewer.ViewportHeight是显示的项目数。

要获得ScrollViewer,您需要一个功能, 将搜索的FindDescendant(FrameworkElement,Type)  在孩子的内心 列表显示。在加载Window之后调用它。

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)

答案 1 :(得分:1)

您可以迭代后续项目,检查其可见性,直到找到不可见的项目。这将为您提供可见项目的计数。

例如:

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

我不确定排序会对此产生什么影响。

答案 2 :(得分:1)

刚刚脱离我的头顶,我没有测试过这个,但你可以这样做:

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

答案 3 :(得分:0)

您是否看过CacheVirtualItems事件?控件将询问一系列项目而不是一个一个。如果滚动,它仍然可能一次只要求一个。但是pagedown / up将触发缓存机制。

答案 4 :(得分:0)

我知道这篇文章很老了..... 错了

MyScrollViewer = FindDescendant(MyListView, ScrollViewer)

权利是:

Dim Myscrollviwer As ScrollViewer

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

答案 5 :(得分:-1)

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;

}

答案 6 :(得分:-1)

试试这个:

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