WPF中DataGridTemplateColumn内ComboBox绑定双属性类问题
问题:WPF DataGrid中绑定PropList类到ComboBox失败
我有一个绑定到DataTable的DataGrid,其中包含一列或多列类型为PropList的列。PropList类包含两个成员:string类型的CurrentValue和List<string>类型的Values。尝试将ComboBox的ItemsSource和SelectedValue绑定到这两个成员,但始终无法成功,已尝试多种方案无效。
相关代码片段
1. PropList类定义
public class PropList { public string CurrentValue; public List<string> Values; public PropList(string val, List<string>list) { CurrentValue = val; Values = list; } }
2. 创建DataTable列
clm = theTable.Columns.Add("The_Model_List", typeof(PropList));
3. DataGrid_AutoGeneratingColumn事件处理
if (e.PropertyType == typeof(PropList)) { var col = new PropListDataGridTemplateColumn { Header = e.PropertyName, ColumnName = e.PropertyName, CellTemplate = (DataTemplate)FindResource("PropListDataTemplate") }; e.Column = col; return; }
4. 自定义PropListDataGridTemplateColumn
//as found on stackoverflow public class PropListDataGridTemplateColumn : DataGridTemplateColumn { public string ColumnName { get; set; } protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) { // The DataGridTemplateColumn uses ContentPresenter with your DataTemplate. var cp = base.GenerateElement(cell, dataItem); // Reset the Binding to the specific column. The default binding is to the DataRowView. cp.SetBinding(ContentPresenter.ContentProperty, new Binding(this.ColumnName)); return cp; } protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { // The DataGridTemplateColumn uses ContentPresenter with your DataTemplate. var cp = base.GenerateElement(cell, dataItem); // Reset the Binding to the specific column. The default binding is to the DataRowView. cp.SetBinding(ContentPresenter.ContentProperty, new Binding(this.ColumnName)); return cp; } }
5. XAML资源与DataGrid定义
<Window.Resources> <ResourceDictionary> <DataTemplate x:Key="PropListDataTemplate" DataType="DataRowView"> <ComboBox HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="1" ItemsSource="{Binding Path=Values}" SelectedValue="{Binding Path=CurrentValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></ComboBox> </DataTemplate> </ResourceDictionary> </Window.Resources> <!-- other stuff --> <DataGrid x:Name="PropData" Margin="5" ItemsSource="{Binding Path=EntityData, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" AlternatingRowBackground="AliceBlue" SelectionUnit="Cell" SelectionMode="Extended" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" SelectedItem="{Binding SelectedEntity, UpdateSourceTrigger=PropertyChanged}" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" CellEditEnding="PropData_CellEditEnding"/>
补充说明:DataGrid的ItemsSource绑定到ViewModel中的DataTable(EntityData),PropList类对应的列已正确绑定,但无法将其两个成员绑定到ComboBox的ItemsSource和SelectedItem属性。
问题原因与解决方案
1. 将字段改为属性(核心问题)
WPF数据绑定仅支持绑定到属性,不支持绑定到字段。需将PropList中的字段改为带get/set访问器的属性:
public class PropList { public string CurrentValue { get; set; } public List<string> Values { get; set; } public PropList(string val, List<string> list) { CurrentValue = val; Values = list; } }
2. 修正DataTemplate的DataType
DataTemplate当前指定的DataType="DataRowView"不符合实际绑定对象(实际绑定的是PropList实例),需修改为:
<!-- 先在XAML头部添加命名空间,替换为你的PropList所在命名空间 --> xmlns:local="clr-namespace:YourNamespace" <DataTemplate x:Key="PropListDataTemplate" DataType="{x:Type local:PropList}"> <ComboBox HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="1" ItemsSource="{Binding Path=Values}" SelectedValue="{Binding Path=CurrentValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </DataTemplate>
3. 修复自定义列的GenerateEditingElement方法
GenerateEditingElement方法中错误调用了base.GenerateElement,应改为base.GenerateEditingElement:
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) { var cp = base.GenerateEditingElement(cell, dataItem); cp.SetBinding(ContentPresenter.ContentProperty, new Binding(this.ColumnName)); return cp; }
4. 可选:实现INotifyPropertyChanged(支持动态更新)
如果需要在CurrentValue或Values变更时自动更新UI,PropList需实现INotifyPropertyChanged接口:
public class PropList : INotifyPropertyChanged { private string _currentValue; public string CurrentValue { get => _currentValue; set { if (_currentValue != value) { _currentValue = value; OnPropertyChanged(nameof(CurrentValue)); } } } private List<string> _values; public List<string> Values { get => _values; set { if (_values != value) { _values = value; OnPropertyChanged(nameof(Values)); } } } public PropList(string val, List<string> list) { CurrentValue = val; Values = list; } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
内容的提问来源于stack exchange,提问作者Jeff Mishler
相关产品推荐
相关产品推荐

