読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

WPFでListBoxで要素が表示されてるか確認してみる

最適解じゃなさそうだけどこんな感じで…。

<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指定されたら破たんするかな…。