Все, что вам нужно сделать, это получить базовую StackPanel, которая находится внутри ListBox.У него достаточно информации о том, какие элементы отображаются.(Он реализует интерфейс IScrollInfo).
Чтобы получить базовый StackPanel (или фактически VirtualizingStackPanel) из заданного ListBox, нам нужно будет использовать 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());
}