获取ListView可见项目

Gam*_*ist 14 .net c# vb.net wpf listview

我有一个ListView可能包含很多物品,所以它是virtualized和回收物品.它不使用排序.我需要刷新一些值显示,但是当项目太多时,更新所有内容的速度太慢,所以我只想刷新可见项目.

我怎样才能获得所有当前显示的项目列表?我试图调查ListView或者在里面ScrollViewer,但我仍然不知道如何实现这一目标.如果可以看到解决方案,解决方案不得通过所有项目进行测试,因为这样做太慢了.

我不确定代码或xaml是否有用,它只是一个Virtualized/ Recycling ListViewItemSource与一个绑定Array.

编辑: 答案:
感谢akjoshi,我找到了方法:

  • 得到ScrollViewerListView (有FindDescendant方法,你可以做你自己用VisualTreeHelper).

  • 读取它ScrollViewer.VerticalOffset:它是显示的第一个项目的编号

  • 读它ScrollViewer.ViewportHeight:它是显示的项目数.
    Rq:CanContentScroll必须是真的.

akj*_*shi 8

在MSDN上查看这个问题,展示一种找出可见ListView项目的技术 -

如何在ListView中找到实际可见的行(ListViewItem(s))?

这是该帖子的相关代码 -

listView.ItemsSource = from i in Enumerable.Range(0, 100) select "Item" + i.ToString();
listView.Loaded += (sender, e) =>
{
    ScrollViewer scrollViewer = listView.GetVisualChild<ScrollViewer>(); //Extension method
    if (scrollViewer != null)
    {
        ScrollBar scrollBar = scrollViewer.Template.FindName("PART_VerticalScrollBar", scrollViewer) as ScrollBar;
        if (scrollBar != null)
        {
            scrollBar.ValueChanged += delegate
            {
                //VerticalOffset and ViweportHeight is actually what you want if UI virtualization is turned on.
                Console.WriteLine("Visible Item Start Index:{0}", scrollViewer.VerticalOffset);
                Console.WriteLine("Visible Item Count:{0}", scrollViewer.ViewportHeight);
            };
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

你应该做的另一件事是用ObservableCollection你的ItemSource而不是Array; 这肯定会提高性能.

更新:

雅可能是真的(array对比ObservableCollection),但我希望看到一些与此相关的统计数据;

真正的好处ObservableCollection是,如果您需要ListView在运行时添加/删除项目,如果您必须Array重新分配其中ItemSourceListViewListView一个并丢弃其先前的项目并重新生成其整个列表.


elb*_*web 8

在尝试找出类似的东西后,我想我会在这里分享我的结果(因为它似乎比其他响应更容易):

我从这里得到的简单可见性测试.

private static bool IsUserVisible(FrameworkElement element, FrameworkElement container)
{
    if (!element.IsVisible)
        return false;

    Rect bounds =
        element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    var rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight);
}
Run Code Online (Sandbox Code Playgroud)

之后,您可以遍历listboxitems并使用该测试来确定哪些是可见的.由于listboxitems始终排序相同,因此该列表中的第一个可见的列表框将是用户的第一个可见的.

private List<object> GetVisibleItemsFromListbox(ListBox listBox, FrameworkElement parentToTestVisibility)
{
    var items = new List<object>();

    foreach (var item in PhotosListBox.Items)
    {
        if (IsUserVisible((ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item), parentToTestVisibility))
        {
            items.Add(item);
        }
        else if (items.Any())
        {
            break;
        }
    }

    return items;
}
Run Code Online (Sandbox Code Playgroud)