我是WPF的新手,我发现WPF .Net 4.0 Datagrid似乎没有处理级联组合框。只有在从一行中删除焦点后,才能使用选择框的正确数据正确填充单元格。我实际上可以看到在关注行丢失之后调试点被击中但是当单元格的焦点丢失时则不会。
这种类型的行为似乎不是前WPF工具包Datagrid的情况,其中一切都符合预期。
这里显而易见的解决方案是使用WPF工具包,但这是.Net 4.0中的一个新项目,所以倒退是没有意义的(也许我会重新考虑这个问题)。我的理解是,WPF工具包有它自己的缺陷份额,这需要我学习和解决这些问题。
我几乎在网上浏览了很多资源,但运气不好。一个反复出现的主题似乎是细胞不是视觉树的一部分,它正在创造这种情况(不确定它是否有效)。
对我可能错过或正在使用的样品的任何帮助都非常感谢。
提前致谢。
情景
WPF .Net 4.0数据网格。
WPF工具包
两个代码几乎相同,减去了WPF Toolkit的使用(样本来自Jialiang's Blog)
CODE
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 });
}
}
}
}
答案 0 :(得分:1)
我总是惊讶于人们如何花费这么多时间来研究一个问题,只是向社区提问,然后在60分钟内找到答案。因此,对WPF来说,新手肯定会有很多分数。
我在以下帖子中找到了答案:wpf-databind-combobox-in-datagrid
显然,就像在所选项目的绑定上设置UpdateSourceTrigger = PropertyChanged一样简单。
来自Microsoft:
“DataGrid编辑模板中的绑定通常将其UpdateSourceTrigger设置为Explicit,因此在用户提交行之前不会更新源属性。您可以通过在ComboBox.SelectedItem的绑定上设置UpdateSourceTrigger = PropertyChanged来覆盖它。” / p>
希望除了我以外的其他人会觉得这很有用。