Note that there are some explanatory texts on larger screens.

plurals
  1. POWPF .Net 4.0 Datagrid, cascading comboboxes not cascading on cell update, only after row update
    text
    copied!<p>I'm new to WPF and I'm finding that the WPF .Net 4.0 Datagrid doesn't appear to handling cascading comboboxes. Only after focus is removed from a row do the cells populate correctly with the right data for selection boxes. I can actually see the debug points being hit after focus on the row is lost but not when focus from a cell is lost.</p> <p>This type of behavior doesn't appear to be the case with the former WPF toolkit Datagrid where everything is as expected.</p> <p>The obvious solution here is to go with the WPF toolkit, yet this is a new project in .Net 4.0 so doesn't make sense to go backwards (perhaps I'll reconsider with this issue). It's also my understanding that the WPF toolkit has it's own share of defects and that would require me to learn and work around as those well.</p> <p>I've pretty much scoured a number of resources on the web and haven't had much luck. One reoccurring theme seems to be that the cells aren't a part of the visual tree which is creating the situation (not sure if that valid or not).</p> <p>Any help on event's I may have missed or working samples are much appreciated.</p> <p>Thanks in advance.</p> <p><strong>SCENARIOS</strong></p> <p><em>WPF .Net 4.0 Data Grid.</em></p> <ol> <li>Starting at row 1.</li> <li>Double click Country cell, change China to United States</li> <li>Double click City cell, notice that Cities are still for China (Not expected)</li> <li>Move focus to row 2.</li> <li>Double click the City cell for row 1 again, notice that the Cities have been updated. New York and Washington are now options.</li> </ol> <p>WPF Toolkit</p> <ol> <li>Starting at row 1.</li> <li>Double click Country cell, change China to United States</li> <li>Double click City cell, notice that Cities are for the United States (expected)</li> </ol> <p>The code is almost identical for the two minus the WPF Toolkit usage (Samples are from <a href="http://geekswithblogs.net/Jialiang/archive/2010/11/30/all-in-one-wpf-code-samples.aspx" rel="nofollow">Jialiang's Blog</a>)</p> <p><strong>CODE</strong></p> <p>WPF .Net 4.0</p> <pre><code>&lt;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"&gt; &lt;DockPanel LastChildFill="True"&gt; &lt;DataGrid Name="dataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False" PreparingCellForEdit="datagrid_PreparingCellForEdit"&gt; &lt;DataGrid.Columns&gt; &lt;DataGridComboBoxColumn x:Name="column1" Width="80"/&gt; &lt;DataGridComboBoxColumn x:Name="column2" Width="80"/&gt; &lt;/DataGrid.Columns&gt; &lt;/DataGrid&gt; &lt;/DockPanel&gt; </code></pre> <p></p> <p>MainWindow.xaml.cs</p> <pre><code>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 &lt; 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 &lt; 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 &lt; 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"); } /// &lt;summary&gt; /// this PreparingCellForEdit event handler gets the hosted editing ComboBox control /// and bind its ItemsSource property according to the value of the Country /// &lt;/summary&gt; 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 }); } } } } </code></pre> <p><strong>WPF Toolkit Code</strong></p> <p>MainWindow.xaml</p> <pre><code>&lt;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"&gt; &lt;DockPanel LastChildFill="True"&gt; &lt;toolkit:DataGrid Name="dataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False" PreparingCellForEdit="datagrid_PreparingCellForEdit"&gt; &lt;toolkit:DataGrid.Columns&gt; &lt;toolkit:DataGridComboBoxColumn x:Name="column1" Width="80"/&gt; &lt;toolkit:DataGridComboBoxColumn x:Name="column2" Width="80"/&gt; &lt;/toolkit:DataGrid.Columns&gt; &lt;/toolkit:DataGrid&gt; &lt;/DockPanel&gt; </code></pre> <p></p> <p>MainWindow.xaml.cs</p> <pre><code>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 &lt; 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 &lt; 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 &lt; 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"); } /// &lt;summary&gt; /// this PreparingCellForEdit event handler gets the hosted editing ComboBox control /// and bind its ItemsSource property according to the value of the Country /// &lt;/summary&gt; 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 }); } } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload