WPF:DataGridヘッダーのクリック時にViewModel側のICommandを実行するための添付プロパティ
上記リンクでBlendのオブジェクトの拡張を作成してTriggerをStyle内に記述する方法での解決があります。 汎用性があるものの、多くのxamlを書く必要があるため、添付プロパティでの解決方法も一応記載してみようと思いました。
<Window x:Class="WpfApplication.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:WpfApplication" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainViewModel/> </Window.DataContext> <Grid> <DataGrid ItemsSource="{Binding Items}" /> </Grid> </Window>
Windowはこんな感じで、
namespace WpfApplication { public class MainViewModel { public List<object> Items { get; } = new List<object>() { new { Item1 = 1, Item2 = "山田" }, new { Item1 = 2, Item2 = "田中" } }; } }
DataContextに入れるVMはこんな感じで。
この画面に、ヘッダークリックイベントを付けていきます。
namespace WpfApplication { public class Attached { public static ICommand GetColumnHeaderClickCommand(DependencyObject obj) { return (ICommand)obj.GetValue(ColumnHeaderClickCommandProperty); } public static void SetColumnHeaderClickCommand(DependencyObject obj, ICommand value) { obj.SetValue(ColumnHeaderClickCommandProperty, value); } // Using a DependencyProperty as the backing store for ColumnHeaderClickCommand. This enables animation, styling, binding, etc... public static readonly DependencyProperty ColumnHeaderClickCommandProperty = DependencyProperty.RegisterAttached("ColumnHeaderClickCommand", typeof(ICommand), typeof(Attached), new PropertyMetadata(null, PropertyChanged)); private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var grid = d as DataGrid; grid.Loaded -= Grid_Loaded; if (e.NewValue != null) grid.Loaded += Grid_Loaded; } private static void Grid_Loaded(object sender, RoutedEventArgs e) { var grid = sender as DataGrid; grid.FindChildren<DataGridColumnHeader>().ToList().ForEach(col => col.Click += Col_Click); } private static void Col_Click(object sender, RoutedEventArgs e) { var header = sender as DataGridColumnHeader; var grid = header.FindParent<DataGrid>(); GetColumnHeaderClickCommand(grid)?.Execute(null); } } public static class Extensions { public static T FindParent<T>(this DependencyObject child) where T : DependencyObject { DependencyObject parentObject = VisualTreeHelper.GetParent(child); if (parentObject == null) return null; T parent = parentObject as T; return parent != null ? parent : FindParent<T>(parentObject); } public static List<T> FindChildren<T>(this DependencyObject parent, List<T> children = null) where T : DependencyObject { if (children == null) children = new List<T>(); if (parent != null) { int childrenCount = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(parent, i); var typeChild = child as T; if (typeChild != null) { children.Add(typeChild); } children = FindChildren<T>(child, children); } } return children; } } }
上記のクラスを作成し、
<Window …> … <Grid> <DataGrid ItemsSource="{Binding Items}" local:Attached.ColumnHeaderClickCommand="{Binding HeaderClickCommand}"/> </Grid> </Window>
上記のように添付プロパティをDataGridに追加し、
namespace WpfApplication { public class MainViewModel { … private RelayCommand _headerClickCommand; /// <summary> /// Gets the HeaderClickCommand. /// </summary> public RelayCommand HeaderClickCommand { get { return _headerClickCommand ?? (_headerClickCommand = new RelayCommand( () => { MessageBox.Show("header clicked"); })); } } } }
ViewModelに上記実装を加えると、クリック時にメッセージボックスが出るようになります。
xamlの変更は少ないのですが、添付プロパティがそこそこの大きさになってしまいました…