WPF .Net 4.0 Datagrid, каскадные комбинированные списки не каскадно при обновлении ячейки, только после обновления строки - PullRequest
0 голосов
/ 14 марта 2011

Я новичок в WPF и обнаружил, что WPF .Net 4.0 Datagrid не работает с каскадными списками.Только после удаления фокуса из строки ячейки правильно заполняются правильными данными для полей выбора.На самом деле я вижу, что точки отладки попадают после потери фокуса на строке, но не при потере фокуса из ячейки.

Этот тип поведения не соответствует предыдущему инструментарию WPF Datagridгде все, как и ожидалось.

Очевидное решение здесь состоит в том, чтобы пойти с инструментарием WPF, но это новый проект в .Net 4.0, поэтому нет смысла возвращаться назад (возможно, я пересмотрю сЭта проблема).Я также понимаю, что инструментарий WPF имеет свою долю недостатков, и это потребовало бы от меня, чтобы я хорошо изучил его и обошел вокруг него.

Я довольно много разобрался с множеством ресурсов в Интернете и укрылся 'мне очень повезло.Одна повторяющаяся тема, по-видимому, состоит в том, что ячейки не являются частью визуального дерева, которое создает ситуацию (не уверен, правильно ли это или нет).

Любая помощь по событиям, которые я мог пропустить или рабочие образцыприветствуются.

Заранее спасибо.

СЦЕНАРИИ

Сетка данных WPF .Net 4.0.

  1. Начиная со строки 1.
  2. Дважды щелкните на ячейке страны, измените Китай на Соединенные Штаты
  3. Дважды щелкните на ячейке города, обратите внимание, что города по-прежнему для Китая (не ожидается)
  4. Переместите фокус на строку 2.
  5. Дважды щелкните ячейку города для строки 1 еще раз, обратите внимание, что Города были обновлены.Теперь можно выбрать Нью-Йорк и Вашингтон.

WPF Toolkit

  1. Начиная со строки 1.
  2. Дважды щелкните ячейку страны, измените Китай на Соединенные Штаты
  3. Дважды щелкните ячейку города, обратите внимание, что города предназначены для Соединенных Штатов (ожидается)

Код практически идентичен для двух, за исключением использования WPF Toolkit (примеры из Блог Цзялян )

КОД

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 });
            }
        }
    }
}

1 Ответ

1 голос
/ 14 марта 2011

Меня всегда удивляет, как можно потратить столько времени на исследование проблемы, только чтобы задать вопрос сообществу, а затем найти ответ в течение 60 минут.Так что, будучи новичком в WPF, он, безусловно, имеет свою долю.

Я нашел ответ в следующем сообщении Microsoft: wpf-databind-combobox-in-datagrid

По-видимому, это так же просто, как установить UpdateSourceTrigger = PropertyChanged на привязку выбранного элемента.

От Microsoft:

"Привязки в шаблонах редактирования DataGrid обычно устанавливают для UpdateSourceTrigger значение Explicit,чтобы исходные свойства не обновлялись до тех пор, пока пользователь не зафиксирует строку. Вы можете переопределить это, установив UpdateSourceTrigger = PropertyChanged в привязке для ComboBox.SelectedItem. "

Надеемся, что кому-то, кроме меня, это будет полезно.*

...