DataGrid, ListView, ListBox などの ItemsControl で複数選択したとき、選択結果は SelectedItems に入っていますが、残念なことにこのプロパティは Binding 非対応です。
バインディングしたい場合は IsSelected プロパティを用意するなど面倒な手順が必要になりますが、実はコマンドで取得するだけなら簡単にできます。
やり方:
- DataGrid 等には x:Name をつけておきます。
<DataGrid x:Name="dataGridName" ItemsSource="{Binding Items}" />
- 使用するコマンドの CommandParameter に、DataGrid 等の SelectedItems を渡します。
<Button Content="選択" Command="{Binding SelectCommand}" CommandParameter="{Binding ElementName=dataGridName, Path=SelectedItems}" />
- VMのコマンド実装では、parameter を受け取って、SelectedItems の型である IList にキャストしてから、中身を項目の型にキャストして使います。
(以下はコマンド実装に ReactiveProperty の ReactiveCommand を使用し、各項目の型は string である場合の例です)
なお、IList はusing System.Collections;
で使用できます。(なぜか Ctrl+. を押しても出てこない・・・)
SelectCommand.Subscribe(parameter => { var selectedItems = ((IList)parameter).Cast<string>().ToArray(); // 以下、selectedItems を使う処理 });
サンプルコード
このサンプルでは、string のリストから複数項目を選択してボタンを押すと、選択された項目群を表示します。
MVVMフレームワークとして ReactiveProperty を使用しています。
xaml(Margin等の指定は省略)
<Window x:Class="WpfTestApp.Windows.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" SizeToContent="WidthAndHeight" ResizeMode="NoResize"> <StackPanel> <DataGrid x:Name="dataGridName" ItemsSource="{Binding Items}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="世界" Binding="{Binding}" /> </DataGrid.Columns> </DataGrid> <Button Content="選択" Command="{Binding SelectCommand}" CommandParameter="{Binding ElementName=dataGridName, Path=SelectedItems}" /> </StackPanel> </Window>
public class MainWindowViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public List<string> Items { get; } = new List<string>() { "Asgard", "Alfheim", "Jotunheim", "Midgard", "Muspelheim", "Nidavellir", "Niflheim", "Svartalfheim", "Vanaheim", }; public ReactiveCommand SelectCommand { get; } = new ReactiveCommand(); // コンストラクタ public MainWindowViewModel() { SelectCommand.Subscribe(parameter => { var selectedItems = ((IList)parameter).Cast<string>().ToArray(); if (selectedItems.Any()) { MessageBox.Show($"あなたは {string.Join(" と ", selectedItems)} を選択しました。"); } }); } }
実行結果
↓