初めに
WPFにてリストビューで選択した要素をCtrl+Cでクリップボードにコピーする実装にて躓いたので解決策を記録します。
Commandを使いまわしたかったのでSelectedIndexのBind以外の方法を検討しました。
結果、リストビューに名前を付けてCommandParameterの引数にElementNameで指定し、PathでSelectedItem(+プロパティ)を指定すればよかったみたいです。
コード
XAML
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>
コードビハインド
MainWindow.xaml.cs
using System.Windows;
namespace CopyByListView;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
ViewModel
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;
}
});
}
リスト要素
クリップボードに転送したい文字列を返すプロパティを実装しています。
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は自分で実装しました。
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;
}
}