XamDataGrid で 2 つコンボ列 (コンボ列 A、コンボ列 B とします) があって、コンボ列 A で選択した値に応じてコンボ列 B のコンボを開いたときの中身を切り替えたい場合 (例えば、下の動画のように、都道府県の値に応じて市区町村の中身を切り替えたい、など)…、

 

これをXamDataGridで実現するには、

1.「都道府県」列のコンボボックスには都道府県のリストをバインドする。
2. 「市区町村」列のコンボボックスでは「都道府県」列で選択されている県の市区町村のリストに動的に作り変え、それをバインドする。

の 2 つを実装することで可能です。

 

1.「都道府県」列のコンボボックスには都道府県のリストをバインドする。

こちらは通常の使い方通りです。ComboBoxField の ItemsSource に都道府県のリストをバインドしてください。

<!-- View (xaml) 側。関連する部分のみ抜粋 -->
<!-- MainWindow.xaml -->

<!-- ItemsSourceに都道府県のリストをバインドする -->
<igDP:ComboBoxField
    Name="PrefectureCode" Label="都道府県"
    ItemsSource="{igDP:FieldBinding Prefectures}" ...>
</igDP:ComboBoxField>
// ViewModel 側。関連する部分のみ抜粋
// MainWindowViewModel.cs

internal class MainWindowViewModel : ObservableObject
{
    ...
    // 都道府県のリストを保持するプロパティ
    private List<Prefecture> _prefectures;
    public List<Prefecture> Prefectures
    {
        get { return _prefectures; }
        set { _prefectures = value; OnPropertyChanged(); }
    }
    ...
}

 

2. 「市区町村」列のコンボボックスでは「都道府県」列で選択されている県の市区町村のリストに動的に作り変え、それをバインドする。

こちらは以下の実装をします。

  • IMultiValueConverter を実装したクラスを作成し、都道府県の値を受け取ってその県に限定した市区町村リストを返す。このオブジェクトを Resources に追加する。
  • ComboBoxField の ItemsSource に「都道府県」列の値をバインドする。
  • すべての市区町村データを XamDataGrid の DataContext に持たせる(※ただしこれは任意。すべての市区町村データをどこに持たせるかは設計次第なので)。
<!-- View (xaml) 側。関連する部分のみ抜粋 -->
<!-- MainWindow.xaml -->

<Window.Resources>
    <!-- 都道府県の値を受け取ってその県に限定した市区町村リストを返す IMultiValueConverter を実装したクラスオブジェクトを Resources に追加する -->
    <local:FilterCitiesByPrefectureCode x:Key="filterCitiesByPrefectureCode"/>
</Window.Resources>

<!-- (中略) -->

<igDP:ComboBoxField Name="CityCode" Label="市">
    <igDP:ComboBoxField.EditorStyle>
        <Style TargetType="{x:Type igEditors:XamComboEditor}">
            <!--
            ComboBoxField の ItemsSource に「都道府県」列の値 (都道府県コード) をバインドする。
            Converter には都道府県コードを受け取ってその県に限定した市区町村のリストを返す Converter を指定する。
            DataContext も Binding しているのは、第一義的には XamDataGrid の仮想化対策のため。
            その他の理由として、今回は XamDataGrid の DataContext にすべての市区町村のデータを持つプロパティがあるという想定にしていて、それを Converter で取り出せるようにするため。
            -->
            <Setter Property="ItemsSource">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource filterCitiesByPrefectureCode}" Mode="OneWay">
                        <!-- DataContext(ここでのDataContextはDataRecord) -->
                        <Binding />
                        <!-- 同じ行の都道府県コード -->
                        <Binding Path="DataItem.PrefectureCode"/>
                    </MultiBinding>
                </Setter.Value>
            </Setter>
            <Setter Property="ValuePath" Value="CityCode"/>
            <Setter Property="DisplayMemberPath" Value="CityName"/>
        </Style>
    </igDP:ComboBoxField.EditorStyle>
</igDP:ComboBoxField>
// ViewModel 側。関連する部分のみ抜粋
// MainWindowViewModel.cs

internal class MainWindowViewModel : ObservableObject
{
    ...
    // すべての市区町村のリストを保持するプロパティ
    private List<City> _cities;
    public List<City> Cities
    {
        get { return _cities; }
        set { _cities = value; OnPropertyChanged(); }
    }
    ...
}
// 都道府県コードを受け取ってその県に限定した市区町村のリストを返す Converter
// FilterCitiesByPrefectureCode.cs

internal class FilterCitiesByPrefectureCode : IMultiValueConverter
{
    // 都道府県コードを受け取り、その都道府県に限定した市区町村のリストを返す。
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // 渡されてきた values が期待した通りかどうかチェックし、
        // 期待していないものが来た場合は何もしない。
        if (values == null || values.Length != 2
            || values[0].GetType() != typeof(DataRecord)
            || values[1].GetType() != typeof(String))
        {
            return Binding.DoNothing;
        }

        // values から DataRecord と PrefectureCode を取得する。
        // さらに、DataRecord からパスをたどって XamDataGrid のデータコンテキストを取り出し、
        // そこから全ての市のリストを取得する。
        var dataRecord = (DataRecord)values[0];
        var prefectureCode = (String)values[1];
        var allCities = (dataRecord.DataPresenter.DataContext as MainWindowViewModel)?.Cities;

        // 同じ PrefectureCode の市のみを取り出し、返す。
        return allCities?.Where(city => city.PrefectureCode == prefectureCode).ToList() ?? Binding.DoNothing;
    }
}

 

 

Tagged:

製品について

Ultimate UI for WPF