如何将DataGridComboBoxColumn.ItemsSource绑定到DataGrid行的不同派生类Enum集合
解决方法
1. 重构基类与派生类,实现枚举的抽象暴露
首先得给基类加两个抽象属性,让每个派生类自行返回对应的枚举选项和选中的命令,同时补全INotifyPropertyChanged的实现——你原来的基类只继承了接口但没实现通知方法,这会导致绑定不更新:
修正后的基类Base
public abstract class Base : INotifyPropertyChanged { public abstract event EventHandler<DataEventArgs> dataUpdate; public string? addr { get; set; } public string? name { get; set; } public string? port { get; set; } // 让派生类返回自己的枚举列表 public abstract IEnumerable<object> CommandOptions { get; } // 保存当前选中的命令,派生类要转成自己的枚举类型 public abstract object SelectedCommand { get; set; } // 实现属性变更通知 public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
调整Derived类
public class Derived : Base { public override event EventHandler<DataEventArgs>? dataUpdate; public enum CMDS { CMD1 = 0x024F032E, CMD2 = 0x0253032A, CMD3 = 0x0252032B, CMD4 = 0x0250032D, CMD5 = 0x0270030D, CMD6 = 0x02570326 } private CMDS _selectedCmd; // 实现基类的选中命令属性,只接受自己的枚举类型 public override object SelectedCommand { get => _selectedCmd; set { if (value is CMDS cmd) { _selectedCmd = cmd; OnPropertyChanged(); } } } // 返回当前类的所有枚举值 public override IEnumerable<object> CommandOptions => Enum.GetValues(typeof(CMDS)).Cast<object>(); }
调整Derived2类
public class Derived2 : Base { public override event EventHandler<DataEventArgs>? dataUpdate; public enum CMDS { CMD1 = 0x024F332E, CMD2 = 0x0224F32A, CMD3 = 0x0252032B } private CMDS _selectedCmd; public override object SelectedCommand { get => _selectedCmd; set { if (value is CMDS cmd) { _selectedCmd = cmd; OnPropertyChanged(); } } } public override IEnumerable<object> CommandOptions => Enum.GetValues(typeof(CMDS)).Cast<object>(); }
2. 用DataGridTemplateColumn替换DataGridComboBoxColumn
DataGridComboBoxColumn的ItemsSource只能绑定到列级上下文,没法拿到当前行的派生类实例,所以必须换成DataGridTemplateColumn,里面嵌套ComboBox,这样就能直接绑定到每行的数据:
修改后的XAML
<DataGrid ItemsSource="{Binding Collection}" AutoGenerateColumns="False" CanUserAddRows="False"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding name}"/> <DataGridTextColumn Header="IP Address" Binding="{Binding addr}"/> <DataGridTextColumn Header="Port" Binding="{Binding port}"/> <!-- 动态加载对应派生类枚举的ComboBox列 --> <DataGridTemplateColumn Header="Command"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding CommandOptions}" SelectedItem="{Binding SelectedCommand, Mode=TwoWay}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding CommandOptions}" SelectedItem="{Binding SelectedCommand, Mode=TwoWay}"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
为什么原来的方法行不通?
- 你之前在基类加
CmdsList的问题:基类不知道具体派生类的枚举,没法动态返回对应的值,而且绑定到Window的DataContext只能拿到基类的属性,区分不了每行的派生类型。 DataGridComboBoxColumn的局限性:它的ItemsSource是列共享的,没法针对每行加载不同的选项,必须用模板列才能实现行级的动态绑定。
内容的提问来源于stack exchange,提问作者gwiz_kid
相关产品推荐
相关产品推荐

