Я новичок в WPF и обнаружил, что WPF .Net 4.0 Datagrid не работает с каскадными списками.Только после удаления фокуса из строки ячейки правильно заполняются правильными данными для полей выбора.На самом деле я вижу, что точки отладки попадают после потери фокуса на строке, но не при потере фокуса из ячейки.
Этот тип поведения не соответствует предыдущему инструментарию WPF Datagridгде все, как и ожидалось.
Очевидное решение здесь состоит в том, чтобы пойти с инструментарием WPF, но это новый проект в .Net 4.0, поэтому нет смысла возвращаться назад (возможно, я пересмотрю сЭта проблема).Я также понимаю, что инструментарий WPF имеет свою долю недостатков, и это потребовало бы от меня, чтобы я хорошо изучил его и обошел вокруг него.
Я довольно много разобрался с множеством ресурсов в Интернете и укрылся 'мне очень повезло.Одна повторяющаяся тема, по-видимому, состоит в том, что ячейки не являются частью визуального дерева, которое создает ситуацию (не уверен, правильно ли это или нет).
Любая помощь по событиям, которые я мог пропустить или рабочие образцыприветствуются.
Заранее спасибо.
СЦЕНАРИИ
Сетка данных WPF .Net 4.0.
- Начиная со строки 1.
- Дважды щелкните на ячейке страны, измените Китай на Соединенные Штаты
- Дважды щелкните на ячейке города, обратите внимание, что города по-прежнему для Китая (не ожидается)
- Переместите фокус на строку 2.
- Дважды щелкните ячейку города для строки 1 еще раз, обратите внимание, что Города были обновлены.Теперь можно выбрать Нью-Йорк и Вашингтон.
WPF Toolkit
- Начиная со строки 1.
- Дважды щелкните ячейку страны, измените Китай на Соединенные Штаты
- Дважды щелкните ячейку города, обратите внимание, что города предназначены для Соединенных Штатов (ожидается)
Код практически идентичен для двух, за исключением использования 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 });
}
}
}
}