我有一个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());
}