DataGrid – SelectedItemsの使い方

C#

SelectedItemはBindingできるのにSelectedItemsはBindingできなくてもどかしいですよね。
Bindingできないないので利用しない人が多いと思いますが、実はオブジェクトも取り出せますし、使ってみると便利ですよ。

Style.TriggerなどでDataGridの内側からSelectedItemsを参照する

DataGridで複数のRowを選択中、という条件を指定したい場合は多いと思います。
無選択ならボタンがdisableで、1つならable、複数選択の時は別の機能に変えたい、って場合があるとします。

これは1例ですが、選択中かつ選択中のアイテムが1つの時、というのを指定しています。

<MultiDataTrigger.Conditions>
    <Condition Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=DataGridRow}}" Value="true" />
    <Condition Binding="{Binding Path=SelectedItems.Count, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="1" />
</MultiDataTrigger.Conditions>

IsSelectedプロパティはDataGridRowのプロパティ、
SelectedItemsプロパティはDataGridのプロパティなので、それぞれRelativeSourceで遡れば取得できます。

ContextMenuからSelectedItemsを参照する

SelectedItemsをBehavior経由でBindingする

SelectedItemsをCommandParameterにBindingする

EventToReactiveCommandでEventArgsからSelectedItemsを取得する

Xaml

<UserControl x:Class="TestApp.Views.Controls.TestView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:interactivity="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.NET46">

    <DataGrid ItemsSource="{Binding Items}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <interactivity:EventToReactiveCommand Command="{Binding SelectionChangedCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </DataGrid>
</UserControl>
ViewModel

public class TestViewModel
{
    public TestViewModel()
    {
        this.SelectedItems= new ObservableCollection<string>()

        this.SelectionChangedCommand = new ReactiveCommand<SelectionChangedEventArgs>()
            .WithSubscribe(e =>
            {
                this.SelectedItems.Clear();
                var items = ((DataGrid)e.Source).SelectedItems;
                foreach(string item in items)
                {
                    this.SelectedItems.Add(item);
                }
            });
    }

    public ObservableCollection<string> SelectedItems{ get; set; }
    public ReactiveCommand<SelectionChangedEventArgs> SelectionChangedCommand { get; set; }
}

EventToReactiveCommandはコントロールのイベントをCommandとして購読できる機能です。
EventArgsを取得して利用する場合は、ReactiveCommand<T>に該当のEventArgsを指定します。
イベントの購読のみでEventArgsが不要な場合は<T>は設定しなくてOKです。

DataGridのSelectionChangedEventはSelectionChangedEventArgsを使います。
SelectionChangedEventArgsの場合、AddedItemsやRemovedItemsがありますが、これらは既に選択中にCtrlクリック等で新たに追加/削除した場合、追加/削除された項目しか取得できません。
選択中の全件を取得するにはDataGridへの参照が必要になります。

((DataGrid)e.Source).SelectedItems
でEventSourceを取得し、SelectedItemsを取得しています。

SelectionChangedEventArgs クラス (System.Windows.Controls)
SelectionChanged イベントのデータを提供します。

EventArgsそのものを渡すとViewModelがViewへの参照を取得できてしまうため、今回の実装はあまり良くありません。必要なSelectedItemsへの参照を渡すだけに限定したい場合は、 ReactiveConverter を使ってReactiveCommandに渡すparameterを加工します。
詳しくは以下の記事を参照してください。

コメント