0

私はWPFを初めて使用しますが、WPF .Net4.0Datagridがカスケードコンボボックスを処理していないように見えます。行からフォーカスが削除された後でのみ、セルに選択ボックスの適切なデータが正しく入力されます。行へのフォーカスが失われた後にデバッグポイントがヒットしているのを実際に確認できますが、セルからのフォーカスが失われた場合は確認できません。

このタイプの動作は、すべてが期待どおりである以前のWPFツールキットDatagridには当てはまらないようです。

ここでの明らかな解決策は、WPFツールキットを使用することですが、これは.Net 4.0の新しいプロジェクトであるため、後戻りする意味はありません(おそらく、この問題について再検討します)。また、WPFツールキットには独自の欠陥があり、それらについても学習して回避する必要があることも理解しています。

私はウェブ上の多くのリソースをかなり精査してきましたが、あまり運がありませんでした。繰り返し発生するテーマの1つは、セルが状況を作成しているビジュアルツリーの一部ではないことです(それが有効かどうかはわかりません)。

私が見逃したかもしれないイベントや作業サンプルに関する助けは大歓迎です。

前もって感謝します。

シナリオ

WPF.Net4.0データグリッド。

  1. 行1から開始します。
  2. 国のセルをダブルクリックし、中国を米国に変更します
  3. Cityセルをダブルクリックし、Citiesがまだ中国向けであることに注意してください(予期されていません)
  4. フォーカスを行2に移動します。
  5. 行1のCityセルをもう一度ダブルクリックし、Citiesが更新されていることを確認します。ニューヨークとワシントンがオプションになりました。

WPFツールキット

  1. 行1から開始します。
  2. 国のセルをダブルクリックし、中国を米国に変更します
  3. [都市]セルをダブルクリックします。都市は米国向けであることに注意してください(予想)

コードは、WPF Toolkitの使用法を除いた2つでほぼ同じです(サンプルはJialiangのブログからのものです)

コード

WPF .Net 4.0

<Window x:Class="CSWPFCascadeDataGridComboBoxColumns.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CSWPFCascadeDataGridComboBoxColumns"    
Title="Cascade DataGridComboBoxColumns" Height="300" Width="300" Loaded="Window_Loaded">
<DockPanel LastChildFill="True">
    <DataGrid Name="dataGrid" ItemsSource="{Binding}" 
                      AutoGenerateColumns="False" 
                      PreparingCellForEdit="datagrid_PreparingCellForEdit">
        <DataGrid.Columns>
            <DataGridComboBoxColumn x:Name="column1" Width="80"/>
            <DataGridComboBoxColumn x:Name="column2" Width="80"/>               
        </DataGrid.Columns>
    </DataGrid>
</DockPanel>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public enum Country
    {
        China,
        UnitedStates
    }
    public enum ChinaCity
    {
        Beijing,
        Shanghai
    }
    public enum UnitedStatesCity
    {
        NewYork,
        Washington
    }

    DataTable table = null;
    string[] strChinaCities, strUnitedStateCities;

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        /////////////////////////////////////////////////////////////////
        // get all enumeration values of type enum Country
        //
        Array countries = Enum.GetValues(typeof(Country));

        /////////////////////////////////////////////////////////////////
        // copy all Country enumeration values to a string array
        //
        string[] strCountries = new string[countries.Length];
        for (int i = 0; i < countries.Length; i++)
        {
            strCountries[i] = (countries as Country[])[i].ToString();
        }

        /////////////////////////////////////////////////////////////////
        // get all enumeration values of type enum ChinaCity
        //
        Array chinaCities = Enum.GetValues(typeof(ChinaCity));

        /////////////////////////////////////////////////////////////////
        // copy all ChinaCity enumeration values to a string array
        //
        strChinaCities = new string[chinaCities.Length];
        for (int i = 0; i < chinaCities.Length; i++)
        {
            strChinaCities[i] = (chinaCities as ChinaCity[])[i].ToString();
        }

        /////////////////////////////////////////////////////////////////
        // get all enumeration values of type enum UnitedStatesCity
        //
        Array unitedStateCities = Enum.GetValues(typeof(UnitedStatesCity));

        /////////////////////////////////////////////////////////////////
        //copy all UnitedStateCity enumeration values to a string array
        //
        strUnitedStateCities = new string[unitedStateCities.Length];
        for (int i = 0; i < unitedStateCities.Length; i++)
        {
            strUnitedStateCities[i] = (unitedStateCities as UnitedStatesCity[])[i].ToString();
        }

        //////////////////////////////////////////////////////////////////
        // combine both the two city enumeration value into one string array
        //
        string[] strAllCities = new string[strChinaCities.Length + strUnitedStateCities.Length];
        strChinaCities.CopyTo(strAllCities, 0);
        strUnitedStateCities.CopyTo(strAllCities, strChinaCities.Length);

        ///////////////////////////////////////////////////////////////////////////////
        // data bind the two DataGridComboBoxColumn's ItemsSource property respectively
        //
        BindingOperations.SetBinding(this.column1, DataGridComboBoxColumn.ItemsSourceProperty,
            new Binding() { Source = strCountries });
        BindingOperations.SetBinding(this.column2, DataGridComboBoxColumn.ItemsSourceProperty,
            new Binding() { Source = strAllCities });

        /////////////////////////////////////////////////////////////////
        // create a DataTable and add two DataColumn into it
        //
        table = new DataTable();
        table.Columns.Add("Country");
        table.Columns.Add("City");

        /////////////////////////////////////////////////////////////////
        // add a DataRow into this DataTable
        //
        table.Rows.Add(new object[] { "China", "Beijing" });

        /////////////////////////////////////////////////////////////////
        // set the DataContext property of the DataGrid to the DataTable
        //
        this.dataGrid.DataContext = table;

        /////////////////////////////////////////////////////////////////
        // set the Header of both DataGridComboBoxColumn and bind the
        // SelectedItemBinding property of both DataGridComboBoxColumn
        this.column1.Header = "Country";
        this.column1.SelectedItemBinding = new Binding("Country");
        this.column2.Header = "City";
        this.column2.SelectedItemBinding = new Binding("City");

    }

    /// <summary>
    /// this PreparingCellForEdit event handler gets the hosted editing ComboBox control 
    /// and bind its ItemsSource property according to the value of the Country
    /// </summary>             
    private void datagrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
    {
        if (e.Column.Header.Equals("City"))
        {
            ComboBox cboEditingElement = e.EditingElement as ComboBox;
            if ((e.Row.Item as DataRowView)["Country"].Equals("China"))
            {
                //////////////////////////////////////////////////////////////////////////
                // bind the ItemsSource property of the cmbEditingElement to China city
                // string array if the selected country is China
                //
                BindingOperations.SetBinding(cboEditingElement, ComboBox.ItemsSourceProperty,
                    new Binding() { Source = strChinaCities });
            }
            else
            {
                //////////////////////////////////////////////////////////////////////////
                // bind the ItemsSource property of the cmbEditingElement to United State
                // city string array if the selected country is United State
                //
                BindingOperations.SetBinding(cboEditingElement, ComboBox.ItemsSourceProperty,
                    new Binding() { Source = strUnitedStateCities });
            }
        }
    }
}

WPFツールキットコード

MainWindow.xaml

<Window x:Class="CSWPFCascadeDataGridComboBoxColumns.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CSWPFCascadeDataGridComboBoxColumns"
xmlns:toolkit ="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="Cascade DataGridComboBoxColumns" Height="300" Width="300" Loaded="Window_Loaded">
<DockPanel LastChildFill="True">
    <toolkit:DataGrid Name="dataGrid" ItemsSource="{Binding}" 
                      AutoGenerateColumns="False" 
                      PreparingCellForEdit="datagrid_PreparingCellForEdit">
        <toolkit:DataGrid.Columns>
            <toolkit:DataGridComboBoxColumn x:Name="column1" Width="80"/>
            <toolkit:DataGridComboBoxColumn x:Name="column2" Width="80"/>               
        </toolkit:DataGrid.Columns>
    </toolkit:DataGrid>
</DockPanel>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public enum Country
    {
        China,
        UnitedStates
    }
    public enum ChinaCity
    {
        Beijing,
        Shanghai
    }
    public enum UnitedStatesCity
    {
        NewYork,
        Washington
    }

    DataTable table = null;
    string[] strChinaCities, strUnitedStateCities;

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        /////////////////////////////////////////////////////////////////
        // get all enumeration values of type enum Country
        //
        Array countries = Enum.GetValues(typeof(Country));

        /////////////////////////////////////////////////////////////////
        // copy all Country enumeration values to a string array
        //
        string[] strCountries = new string[countries.Length];
        for (int i = 0; i < countries.Length; i++)
        {
            strCountries[i] = (countries as Country[])[i].ToString();
        }

        /////////////////////////////////////////////////////////////////
        // get all enumeration values of type enum ChinaCity
        //
        Array chinaCities = Enum.GetValues(typeof(ChinaCity));

        /////////////////////////////////////////////////////////////////
        // copy all ChinaCity enumeration values to a string array
        //
        strChinaCities = new string[chinaCities.Length];
        for (int i = 0; i < chinaCities.Length; i++)
        {
            strChinaCities[i] = (chinaCities as ChinaCity[])[i].ToString();
        }

        /////////////////////////////////////////////////////////////////
        // get all enumeration values of type enum UnitedStatesCity
        //
        Array unitedStateCities = Enum.GetValues(typeof(UnitedStatesCity));

        /////////////////////////////////////////////////////////////////
        //copy all UnitedStateCity enumeration values to a string array
        //
        strUnitedStateCities = new string[unitedStateCities.Length];
        for (int i = 0; i < unitedStateCities.Length; i++)
        {
            strUnitedStateCities[i] = (unitedStateCities as UnitedStatesCity[])[i].ToString();
        }

        //////////////////////////////////////////////////////////////////
        // combine both the two city enumeration value into one string array
        //
        string[] strAllCities = new string[strChinaCities.Length + strUnitedStateCities.Length];
        strChinaCities.CopyTo(strAllCities, 0);
        strUnitedStateCities.CopyTo(strAllCities, strChinaCities.Length);

        ///////////////////////////////////////////////////////////////////////////////
        // data bind the two DataGridComboBoxColumn's ItemsSource property respectively
        //
        BindingOperations.SetBinding(this.column1, DataGridComboBoxColumn.ItemsSourceProperty,
            new Binding() { Source = strCountries });
        BindingOperations.SetBinding(this.column2, DataGridComboBoxColumn.ItemsSourceProperty,
            new Binding() { Source = strAllCities });

        /////////////////////////////////////////////////////////////////
        // create a DataTable and add two DataColumn into it
        //
        table = new DataTable();
        table.Columns.Add("Country");
        table.Columns.Add("City");

        /////////////////////////////////////////////////////////////////
        // add a DataRow into this DataTable
        //
        table.Rows.Add(new object[] { "China", "Beijing" });

        /////////////////////////////////////////////////////////////////
        // set the DataContext property of the DataGrid to the DataTable
        //
        this.dataGrid.DataContext = table;

        /////////////////////////////////////////////////////////////////
        // set the Header of both DataGridComboBoxColumn and bind the
        // SelectedItemBinding property of both DataGridComboBoxColumn
        this.column1.Header = "Country";
        this.column1.SelectedItemBinding = new Binding("Country");
        this.column2.Header = "City";
        this.column2.SelectedItemBinding = new Binding("City");

    }

    /// <summary>
    /// this PreparingCellForEdit event handler gets the hosted editing ComboBox control 
    /// and bind its ItemsSource property according to the value of the Country
    /// </summary>             
    private void datagrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
    {
        if (e.Column.Header.Equals("City"))
        {
            ComboBox cboEditingElement = e.EditingElement as ComboBox;
            if ((e.Row.Item as DataRowView)["Country"].Equals("China"))
            {
                //////////////////////////////////////////////////////////////////////////
                // bind the ItemsSource property of the cmbEditingElement to China city
                // string array if the selected country is China
                //
                BindingOperations.SetBinding(cboEditingElement, ComboBox.ItemsSourceProperty,
                    new Binding() { Source = strChinaCities });
            }
            else
            {
                //////////////////////////////////////////////////////////////////////////
                // bind the ItemsSource property of the cmbEditingElement to United State
                // city string array if the selected country is United State
                //
                BindingOperations.SetBinding(cboEditingElement, ComboBox.ItemsSourceProperty,
                    new Binding() { Source = strUnitedStateCities });
            }
        }
    }
}
4

1 に答える 1

3

問題の調査に多くの時間を費やし、コミュニティに質問してから 60 分以内に答えを見つけることができることに、いつも驚かされます。そのため、WPF を初めて使用する場合は、確かにかなりの部分を占める必要があります。

UpdateSourceTrigger=PropertyChangedどうやら、選択したアイテムのバインディングに設定するのと同じくらい簡単です。

マイクロソフトから:

DataGrid の編集テンプレートのバインディングは通常、UpdateSourceTrigger を Explicit に設定するため、ユーザーが行をコミットするまでソース プロパティは更新されません。これは、ComboBox.SelectedItem のバインディングで UpdateSourceTrigger=PropertyChanged を設定することでオーバーライドできます。"

うまくいけば、私以外の誰かがこれが役に立つと思うでしょう。

于 2011-03-14T15:32:44.287 に答える