DataGrid内のボタンを親のクラスで受け取る
下記ソースの場合、ボタンを押下すると、行ごとのクラス内のイベントが発生してしまう。
MainView.xaml
<Window x:Class="WpfApp6.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:WpfApp6"
xmlns:vm="clr-namespace:WpfApp6.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="300">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<Grid>
<DataGrid Margin="10" ItemsSource="{Binding Path=ArrayData}" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="BorderThickness" Value="0" />
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Index" Binding="{Binding Path=Index}" />
<DataGridTemplateColumn Header="名前">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="{Binding Path=Name}" Command="{Binding Path=ClickItem}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="値段" Binding="{Binding Path=Price}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
namespace WpfApp6.ViewModel
{
public class MainViewModel : INotifyPropertyChangedBase
{
private ObservableCollection<ItemPriceData> _ArrayData = new ObservableCollection<ItemPriceData>();
public ObservableCollection<ItemPriceData> ArrayData
{
get
{
return _ArrayData;
}
set
{
_ArrayData = value;
OnPropertyChanged();
}
}
private ICommand _ClickItem;
public ICommand ClickItem
{
get
{
return _ClickItem ?? (_ClickItem = new RelayCommand(() => { MessageBox.Show("MainViewModel内のClickItem"); }));
}
}
public MainViewModel()
{
ArrayData.Add(new ItemPriceData(0, "りんご", 150));
ArrayData.Add(new ItemPriceData(1, "みかん", 200));
ArrayData.Add(new ItemPriceData(2, "バナナ", 380));
}
}
public class ItemPriceData : INotifyPropertyChangedBase
{
private int _Index;
public int Index
{
get
{
return _Index;
}
set
{
_Index = value;
OnPropertyChanged();
}
}
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
OnPropertyChanged();
}
}
private int _Price;
public int Price
{
get
{
return _Price;
}
set
{
_Price = value;
OnPropertyChanged();
}
}
public ItemPriceData(int intIndex, string strName, int intPrice)
{
Index = intIndex;
Name = strName;
Price = intPrice;
}
private ICommand _ClickItem;
public ICommand ClickItem
{
get
{
return _ClickItem ?? (_ClickItem = new RelayCommand(() => { MessageBox.Show("ItemPriceData内のClickItem"); }));
}
}
}
public class INotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RelayCommand : ICommand
{
private Action _action;
public RelayCommand(Action action)
{
_action = action;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _action != null;
}
public void Execute(object parameter)
{
_action?.Invoke();
}
}
}

ボタンのCommandのバインドを下記のように修正することで、
親で受け取ることができる。
<Button Content="{Binding Path=Name}" Command="{Binding Path=DataContext.ClickItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />

また、ボタンにCommandParameterを設定し、RelayCommandを引数対応に修正することで、
どのボタンが押されたかを親で取得することができる。
MainView.xaml
<Window x:Class="WpfApp6.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:WpfApp6"
xmlns:vm="clr-namespace:WpfApp6.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="300">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<Grid>
<DataGrid Margin="10" ItemsSource="{Binding Path=ArrayData}" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="BorderThickness" Value="0" />
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Index" Binding="{Binding Path=Index}" />
<DataGridTemplateColumn Header="名前">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="{Binding Path=Name}" Command="{Binding Path=DataContext.ClickItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding Path=Index}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="値段" Binding="{Binding Path=Price}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainViewModel
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
namespace WpfApp6.ViewModel
{
public class MainViewModel : INotifyPropertyChangedBase
{
private ObservableCollection<ItemPriceData> _ArrayData = new ObservableCollection<ItemPriceData>();
public ObservableCollection<ItemPriceData> ArrayData
{
get
{
return _ArrayData;
}
set
{
_ArrayData = value;
OnPropertyChanged();
}
}
private ICommand _ClickItem;
public ICommand ClickItem
{
get
{
return _ClickItem ?? (_ClickItem = new RelayCommand((object param) =>
{
MessageBox.Show(_ArrayData.First(t => t.Index == (int)param).Name);
}));
}
}
public MainViewModel()
{
ArrayData.Add(new ItemPriceData(0, "りんご", 150));
ArrayData.Add(new ItemPriceData(1, "みかん", 200));
ArrayData.Add(new ItemPriceData(2, "バナナ", 380));
}
}
public class ItemPriceData : INotifyPropertyChangedBase
{
private int _Index;
public int Index
{
get
{
return _Index;
}
set
{
_Index = value;
OnPropertyChanged();
}
}
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
OnPropertyChanged();
}
}
private int _Price;
public int Price
{
get
{
return _Price;
}
set
{
_Price = value;
OnPropertyChanged();
}
}
public ItemPriceData(int intIndex, string strName, int intPrice)
{
Index = intIndex;
Name = strName;
Price = intPrice;
}
private ICommand _ClickItem;
public ICommand ClickItem
{
get
{
return _ClickItem ?? (_ClickItem = new RelayCommand((object param) => { MessageBox.Show("ItemPriceData内のClickItem"); }));
}
}
}
public class INotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RelayCommand : ICommand
{
private Action<object> _action;
public RelayCommand(Action<object> action)
{
_action = action;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _action != null;
}
public void Execute(object parameter)
{
_action?.Invoke(parameter);
}
}
}

ディスカッション
コメント一覧
まだ、コメントがありません