wpf – 在ListBox中记录用户可见的项目

我有一个ListBox或DataGrid填充了数以千计的条目.我想知道用户查看的项目(滚动,搜索或其他).如何判断ListBox中用户可见的内容?

奖励:设置一个计时器,使项目必须显示至少N毫秒(如果用户只是拉下滚动条).

更新:这是一个接近重复的Get items in view within a listbox – 但它使用“SelectedItems”给出的解决方案是不够的.我需要知道它们是否被选中的项目!

最佳答案 您需要做的就是获取ListBox中的底层StackPanel.它有足够的信息显示哪些元素正在显示. (它实现了接口IScrollInfo).

要从给定的ListBox获取底层StackPanel(或实际上是VirtualizingStackPanel),我们必须使用VisualTreeHelper来浏览Visual Tree并查找VirtualizingStackPanel,如下所示:

    private VirtualizingStackPanel GetInnerStackPanel(FrameworkElement element)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
        {
            var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;

            if (child == null) continue;

            Debug.WriteLine(child.ToString());

            if (child is VirtualizingStackPanel) return child as VirtualizingStackPanel;

            var panel = GetInnerStackPanel(child);

            if (panel != null)
                return panel;
        }

        return null;

    }

现在我们有StackPanel,我们非常接近. StackPanel具有属性VerticalOffset和ViewportHeight(均来自IScrollInfo),可以为我们提供所需的所有信息.

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        var theStackPanel = GetInnerStackPanel(MyListBox);

        List<FrameworkElement> visibleElements = new List<FrameworkElement>();

        for (int i = 0; i < theStackPanel.Children.Count; i++)
        {

            if (i >= theStackPanel.VerticalOffset && i <= theStackPanel.VerticalOffset + theStackPanel.ViewportHeight)
            {
                visibleElements.Add(theStackPanel.Children[i] as FrameworkElement);
            }
        }


        MessageBox.Show(visibleElements.Count.ToString());
        MessageBox.Show(theStackPanel.VerticalOffset.ToString());
        MessageBox.Show((theStackPanel.VerticalOffset + theStackPanel.ViewportHeight).ToString());

    }
点赞