最適解じゃなさそうだけどこんな感じで…。
<Window x:Class="WpfApplication5.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApplication5" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition /> </Grid.RowDefinitions> <Button Content="Dump" Click="ButtonDump_Click" /> <ListBox x:Name="ListBox" Grid.Row="1"> </ListBox> </Grid> </Window>
ContainerFromItemで要素がとれなかったらそもそも表示されてない。ContainerFromItemでインスタンスが取れたら、ListBoxからの相対座標がListBoxの矩形領域に収まってたら表示されてるみたいな。
using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace WpfApplication5 { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.ListBox.ItemsSource = Enumerable.Range(1, 20) .Select(x => new Person { Name = $"tanaka {x}" }) .ToArray(); } private void ButtonDump_Click(object sender, RoutedEventArgs e) { var box = VisualTreeHelper.GetDescendantBounds(this.ListBox); foreach (var item in this.ListBox.ItemsSource.Cast<Person>()) { var container = this.ListBox.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem; if (container == null) { Debug.WriteLine($"表示されてない: {item.Name}"); continue; } var top = container.TranslatePoint(new Point(), this.ListBox); if (box.Contains(top)) { Debug.WriteLine($"表示されてる: {item.Name}"); } else { Debug.WriteLine($"表示されてない: {item.Name}"); } } } } public class Person { public string Name { get; set; } public override string ToString() { return this.Name; } } }
でも、Padding指定されたら破たんするかな…。