久しぶりのWPFネタです。小ネタ。
DataGridComboBoxColumnクラスを使うと、簡単にDataGridにComboBoxを設定できます。しかし、DataGridComboBoxColumnクラスのItemsSourceプロパティをBindingしようとすると、BindingのSourceがWindowのDataContextではなく、DataGridのItemsSourceに設定されたコレクションの行に該当するオブジェクトがSourceとして使用されます。そのため、WindowのDataContextが持っているコレクションを表示しようとするだけでも、Bindingが多少複雑になります。
AncestorTypeなどを使って親要素を辿ったりということを考えがちですが、もっと簡単なやり方があります。WindowのResourcesにCollectionViewSourceを使って、DataContextのコレクションをStaticResourceで参照出来るようにして、DataGridComboBoxColumnのItemsSourceにバインドする方法です。コード例を以下に示します。
まずDataGridの行に該当するクラスとして、以下のPersonクラスを定義します。このPersonクラスのParentIdをComboBoxから選択するという機能を実装します。
publicclass Person : INotifyPropertyChanged { publicevent PropertyChangedEventHandler PropertyChanged; privatevoid SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null) { field = value; var h = this.PropertyChanged; if (h != null) { h(this, new PropertyChangedEventArgs(propertyName)); } } privatestring id; publicstring Id { get { returnthis.id; } set { this.SetProperty(refthis.id, value); } } privatestring name; publicstring Name { get { returnthis.name; } set { this.SetProperty(refthis.name, value); } } privatestring parentId; publicstring ParentId { get { returnthis.parentId; } set { this.SetProperty(refthis.parentId, value); } } public Person() { this.Id = Guid.NewGuid().ToString(); } }
続けて、MainWindowのViewModelを作成します。今回は以下のようなPersonクラスのコレクションを持っただけのシンプルなものになります。
publicclass MainWindowViewModel { public ObservableCollection<Person> People { get; private set; } public MainWindowViewModel() { this.People = new ObservableCollection<Person>( Enumerable.Range(1, 100).Select(x => new Person { Name = "okazuki" + x })); } }
このクラスをMainWindowのDataContextに設定して、DataGridに表示します。そして、ParentIdプロパティをPeopleコレクションの中から選択出来るようにします。XAMLは以下のようになります。
<Window x:Class="MVVMDataGridComboboxColumnSample.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:l="clr-namespace:MVVMDataGridComboboxColumnSample"Title="MainWindow"Height="350"Width="525"><Window.DataContext><l:MainWindowViewModel /></Window.DataContext><Window.Resources><!-- CollectionViewSourceで参照出来るようにしておいて --><CollectionViewSourcex:Key="PeopleSource"Source="{Binding People}" /></Window.Resources><Grid><DataGridAutoGenerateColumns="False"ItemsSource="{Binding People}"><DataGrid.Columns><DataGridTextColumnHeader="名前"Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /><!-- DataGridComboBoxColumnのItemsSourceで使用する --><DataGridComboBoxColumnHeader="親"SelectedValuePath="Id"DisplayMemberPath="Name"ItemsSource="{Binding Source={StaticResource PeopleSource}}"SelectedValueBinding="{Binding ParentId}"/></DataGrid.Columns></DataGrid></Grid></Window>
WindowのResourcesにPeopleをCollectionViewSourceとして登録しているため、簡単にDataGridComboBoxColumnのItemsSourceが設定できています。実行結果を以下に示します。