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();
}
}
}
0 件のコメント:
コメントを投稿