TreeViewで項目が選択されたらスクロールする

2026年7月17日金曜日

.NET WPF C#

ViewModelから項目を選択したときにTreeViewは勝手にスクロールして選択された項目を表示してくれたりはしません。自動でスクロールさせるためにTreeViewの拡張メソッドとビヘイビアを作りました。仮想化していないTreeViewに対応しています。

環境

.NET 10、C#、WPF

必要なもの

NuGetパッケージ

  • Microsoft.Xaml.Behaviors.Wpf

拡張メソッド

using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Common.Extensions
{
    /// <summary>
    /// TreeView の拡張メソッドです。
    /// </summary>
    public static class TreeViewExtensions
    {
        /// <summary>
        /// 条件を満たす TreeViewItem を探します。
        /// </summary>
        /// <param name="treeView"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static TreeViewItem? FindItemContainer(this TreeView treeView, Func<TreeViewItem, bool> predicate)
        {
            return FindItemContainerRecursively(treeView, predicate);
        }

        private static TreeViewItem? FindItemContainerRecursively(ItemsControl itemsControl, Func<TreeViewItem, bool> predicate)
        {
            if ((itemsControl.ItemContainerGenerator is not ItemContainerGenerator itemContainerGenerator)
                || !(itemContainerGenerator.Status is GeneratorStatus.ContainersGenerated or GeneratorStatus.GeneratingContainers))
            {
                return null;
            }

            foreach (object item in itemsControl.Items)
            {
                if (itemContainerGenerator.ContainerFromItem(item) is not TreeViewItem child)
                {
                    continue;
                }

                if (predicate(child))
                {
                    return child;
                }

                if (FindItemContainerRecursively(child, predicate) is TreeViewItem found)
                {
                    return found;
                }
            }

            return null;
        }

        /// <summary>
        /// 選択されている TreeViewItem を探します。
        /// </summary>
        /// <param name="treeView"></param>
        /// <returns></returns>
        public static TreeViewItem? FindSelectedItemContainer(this TreeView treeView)
        {
            return treeView.FindItemContainer((treeViewItem) => treeViewItem.IsSelected);
        }
    }
}

ビヘイビア

using Common.Extensions;
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;

namespace Common.Behaviors
{
    /// <summary>
    /// ScrollToSelectedItemBehavior は TreeView の拡張です。
    /// ScrollToSelectedItemBehavior を関連付けた TreeView は選択した項目が表示されるようにスクロールします。
    /// </summary>
    public class EnsureSelectedItemVisibleBehavior : Behavior<TreeView>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.SelectedItemChanged += TreeView_SelectedItemChanged;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.SelectedItemChanged -= TreeView_SelectedItemChanged;
        }

        private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            TreeViewItem? selectedItem = AssociatedObject.FindSelectedItemContainer();
            selectedItem?.BringIntoView();
        }
    }
}

仮想化したTreeViewに対応するなら

こういう方法になるそうです。「方法: TreeView で TreeViewItem を検索する - WPF | Microsoft Learn」(https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/how-to-find-a-treeviewitem-in-a-treeview)

rommxbbu6v6

.NET、C#、WPFの話題が多いです。

人気の投稿 / 新着記事

人気記事 新着記事
  • 読み込み中...

人気の投稿 ※消さないでください

ラベル

.NET (2) C# (2) WPF (2)

ブログ アーカイブ

目次

このブログを検索