Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

WPF の TreeView で任意の項目が表示されるようにスクロールする

$
0
0

というネタを見つけたのでやってみます。久しぶりの WPF ネタ!因みにせっかくなので .NET Core 3.0 Preview 7 で VS2019 Preview 使ってやってみます。

表示用データはこれ!

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace TreeViewScrollSample
{
    publicclass Person
    {
        publicstring Name { get; set; }
        public IEnumerable<Person> Children { get; set; }
    }
}

画面が側はこんな感じでいきましょう。

<Windowx:Class="TreeViewScrollSample.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:local="clr-namespace:TreeViewScrollSample"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="800"Height="450"mc:Ignorable="d"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition /></Grid.RowDefinitions><Button Click="ScrollButton_Click"Content="Scroll" /><TreeView x:Name="treeView"Grid.Row="1"><TreeView.ItemTemplate><HierarchicalDataTemplate ItemsSource="{Binding Children}"><TextBlock Text="{Binding Name}" /></HierarchicalDataTemplate></TreeView.ItemTemplate></TreeView></Grid></Window>

これで、こんな感じでコードを書けばスクロールします。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace TreeViewScrollSample
{
    /// <summary>/// Interaction logic for MainWindow.xaml/// </summary>publicpartialclass MainWindow : Window
    {
        private IEnumerable<Person> People { get; } = Enumerable.Range(1, 100)
            .Select(x => new Person
            {
                Name = $"Tanaka {x}",
                Children = Enumerable.Range(1, 10)
                    .Select(y => new Person
                    {
                        Name = $"Kimura {x}-{y}",
                    })
                    .ToArray(),
            })
            .ToArray();

        public MainWindow()
        {
            InitializeComponent();
            treeView.ItemsSource = People;
        }

        private async void ScrollButton_Click(object sender, RoutedEventArgs e)
        {
            // ContainersGenerated になるまで待つ
            Task waitUntilContainersGenerated(TreeViewItem container)
            {
                var tcs = new TaskCompletionSource<object>(container);
                void statusChanged(object _, EventArgs __)
                {
                    if (container.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                    {
                        tcs.SetResult(null);
                        container.ItemContainerGenerator.StatusChanged -= statusChanged;
                        return;
                    }
                }

                container.ItemContainerGenerator.StatusChanged += statusChanged;
                return tcs.Task;
            }

            // 一番最後の最後の要素にスクロールする予定
            var parent = People.Last();
            var target = parent.Children.Last();

            // ツリービュー直下の最後の要素のTreeViewItemを取得
            var container = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(parent);
            // 開く
            container.IsExpanded = true;
            // 子の ItemContainerGenerator のステータスが Generated になるまで待つif (container.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
            {
                await waitUntilContainersGenerated(container);
            }

            // スクロール先を取得してスクロール
            var targetContainer = (TreeViewItem)container.ItemContainerGenerator.ContainerFromItem(target);
            targetContainer.BringIntoView();
        }
    }
}

実行すると…

f:id:okazuki:20190725111302g:plain

動いた!!

ソースコードは GitHub に上げておきました。

github.com


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>