How do I get the start index and number of visible items in a ListView?

无人久伴 提交于 2019-11-28 08:57:11

问题


I have a listview working in virtual mode, in the LargeIcons view. Retrieves are expensive, so I want to ask for the data for all the visible items. How do I get the start index and total number of the visible items?

Update: I am aware of the CacheVirtualItems event. The third-party database we're using takes ~3s to retrieve a single record, but ~4s to retrieve a thousand records, so I have to do them in large blocks. I need to make sure the visible records are among those we retrieve, so I need to know the start index and total number of the visible items. If that's not feasible, I'll have to find a workaround (which will probably involve using a DataGridView with a load of image cells to imitate the LargeIcons view) but I would like to do this properly if possible.


回答1:


THE REAL Answer is :
* get the ScrollViewer of the ListView.
* ScrollViewer.VerticalOffset is the index of first shown item.
* ScrollViewer.ViewportHeight is the number of items shown.

To get the ScrollViewer, you will need a function, FindDescendant(FrameworkElement, Type) that will search within the childs of the ListView. Call it after Window was loaded.

Code in VB.Net and in 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)



回答2:


Just off the top of my head, and I haven't tested this but could you do:

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:


You could iterate through subsequent items, checking their visibility until you reach the one that isn't visible. This would give you a count of the visible items.

For example, something like:

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

I'm not sure what effect sorting would have on this though.




回答4:


Have you seen the CacheVirtualItems event? The control will ask for a range of items instead of one-by-one. Tho, if scrolling, it still may ask for only one at a time. But pagedown/up will trigger the cache mechanism.




回答5:


I know this post is old ..... Wrong

MyScrollViewer = FindDescendant(MyListView, ScrollViewer)

Right is:

Dim Myscrollviwer As ScrollViewer

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



回答6:


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;

}



回答7:


Try this:

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


来源:https://stackoverflow.com/questions/372011/how-do-i-get-the-start-index-and-number-of-visible-items-in-a-listview

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!