【WPF】CommandParameterにListViewのSelectedItemを渡す

## 初めに
WPFにてリストビューで選択した要素をCtrl+Cでクリップボードにコピーする実装にて躓いたので解決策を記録します。
Commandを使いまわしたかったのでSelectedIndexのBind以外の方法を検討しました。
結果、リストビューに名前を付けてCommandParameterの引数にElementNameで指定し、PathでSelectedItem（＋プロパティ）を指定すればよかったみたいです。
# コード
### XAML
```xml:MainWindow.xaml
<Window x:Class="CopyByListView.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:CopyByListView"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <ListView Name="listView" 
                  HorizontalContentAlignment="Stretch"
                  ItemsSource="{Binding MyList}">
            <ListView.InputBindings>
                <KeyBinding Gesture="Ctrl+C" 
                    Command="{Binding CopyCommand}"
                    CommandParameter="{Binding ElementName=listView, Path=SelectedItem.Full}"/>
            </ListView.InputBindings>
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="上の句" DisplayMemberBinding="{Binding FirstHalf}"/>
                    <GridViewColumn Header="下の句" DisplayMemberBinding="{Binding LastHalf}"/>
                    <GridViewColumn Header="詠み人" DisplayMemberBinding="{Binding Writer}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

```
### コードビハインド
```csharp:MainWindow.xaml.cs
using System.Windows;

namespace CopyByListView;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}
```
### ViewModel
```csharp:MainWindowViewModel.cs
using System.Collections.ObjectModel;
using System.Windows;

namespace CopyByListView;

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        MyList = new ObservableCollection<MyListItem>
        {
            new MyListItem() { FirstHalf="秋の田の　かりほの庵の　苫をあらみ", LastHalf="わが衣手は　露にぬれつつ", Writer="天智天皇"},
            new MyListItem() { FirstHalf="春すぎて　夏来にけらし　白たへの", LastHalf="ころもほすてふ　あまの香具山", Writer="持統天皇"},
            new MyListItem() { FirstHalf="あしひきの　山鳥の尾の　しだり尾の", LastHalf="ながながし夜を　ひとりかも寝む", Writer="柿本人麻呂"},
            new MyListItem() { FirstHalf="田子の浦に　うちいでて見れば　白たへの", LastHalf="富士の高嶺に　雪は降りつつ", Writer="山部赤人"},
            new MyListItem() { FirstHalf="奥山に　もみぢ踏み分け　鳴く鹿の", LastHalf="声聞く時ぞ　秋は悲しき", Writer="猿丸太夫"},
            new MyListItem() { FirstHalf="かささぎの　渡せる橋に　おく霜の", LastHalf="白きを見れば　夜ぞふけにける", Writer="中納言家持"},
            new MyListItem() { FirstHalf="あまの原　ふりさけ見れば　かすがなる", LastHalf="三笠の山に　いでし月かも", Writer="安倍仲麿"},
            new MyListItem() { FirstHalf="わが庵は　都のたつみ　しかぞ住む", LastHalf="世を宇治山と　人は言ふなり", Writer="喜撰法師"},
        };
    }

    public ObservableCollection<MyListItem> MyList { get; }

    public DelegateCommand CopyCommand => new(
        (param) =>
        {
            if (param is string text)
            {
                Clipboard.SetText(text);
                MessageBox.Show($"クリップボードにコピーしました\r\n [{text}]");
                return;
            }
        });
}
```

### リスト要素
クリップボードに転送したい文字列を返すプロパティを実装しています。
```csharp:MyListItem
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace CopyByListView;

public class MyListItem : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    private string _firstHalf = string.Empty;
    public string FirstHalf
    {
        get => _firstHalf;
        set
        {
            _firstHalf = value;
            NotifyPropertyChanged();
        }
    }

    private string _lastHalf = string.Empty;
    public string LastHalf
    {
        get => _lastHalf;
        set
        {
            _lastHalf = value;
            NotifyPropertyChanged();
        }
    }

    private string _writer = string.Empty;
    public string Writer
    {
        get => _writer;
        set
        {
            _writer = value;
            NotifyPropertyChanged();
        }
    }

    public string Full => $"{FirstHalf}　{LastHalf}　{Writer}";
}

```

### DelegeteCommand
なお、DelegeteCommandは自分で実装しました。

```csharp:DelegeteCommand.cs
using System;
using System.Windows.Input;

namespace CopyByListView;

public class DelegateCommand : ICommand
{
    private Action<object?> _execute;

    public DelegateCommand(Action<object?> execute)
    {
        _execute = execute;
    }

    public bool CanExecute(object? parameter) => true;

    public void Execute(object? parameter) => _execute?.Invoke(parameter);

    public event EventHandler? CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }
}
```

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/2f64b077-cefe-7be8-e1b3-4b556eebd7ce.png)
↓　選択してCtrl+C
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/9aaa0d9c-b038-982e-e06e-b1d7d789bdb4.png)
OK!