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();
        }
    }
}
```

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450485/29849dee-255a-a174-6c61-3706167cef00.png)

ボタンのCommandのバインドを下記のように修正することで、
親で受け取ることができる。

```
<Button Content="{Binding Path=Name}" Command="{Binding Path=DataContext.ClickItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" />
```

![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450485/bef38efd-a953-f4fb-5512-b1c8ed6446ed.png)

また、ボタンに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);
        }
    }
}
```

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450485/74528f42-8dfc-d8da-fea0-5bad5dabe75a.png)