我是WPF的新手,我发现WPF .Net 4.0 Datagrid似乎没有处理级联组合框。只有将焦点从一行中移出后,单元格才能正确填充选择框的正确数据。我实际上可以看到在失去对行的焦点之后击中了调试点,但是在失去单元格的焦点时却看不到。
[这种行为在以前的WPF工具包Datagrid中似乎并非如此,在这里一切都按预期进行。
显而易见的解决方案是使用WPF工具包,但这是.Net 4.0中的一个新项目,因此往后退是没有意义的(也许我会重新考虑这个问题)。根据我的理解,WPF工具包也有其自身的缺陷,这将需要我学习和解决这些缺陷。
我几乎已经在网上搜索了许多资源,但运气并不好。一个经常发生的主题似乎是这些单元格不是正在创建情况的视觉树的一部分(不确定是否有效)。
对我可能错过的活动或工作样品的任何帮助,将不胜感激。
提前感谢。
SCENARIOS
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 });
}
}
}
}
我是WPF的新手,我发现WPF .Net 4.0 Datagrid似乎没有处理级联组合框。只有将焦点从一行中移出后,单元格才能正确地填充右侧...
[总是让我感到惊讶的是,如何花这么多时间研究一个问题,然后向社区提出问题,然后在60分钟内找到答案。因此,对于WPF来说,新手肯定有很多需要注意的地方。