如何在DataGridViewComboBox中显示枚举类型成员?

11

我还需要做什么才能在这个DataGridViewComboBox中显示ReadAccess枚举成员?

ReadDataGridViewComboBoxColumn.Items.Clear();
ReadDataGridViewComboBoxColumn.Items.AddRange(ReadAccess.None, ReadAccess.Allowed);
ReadDataGridViewComboBoxColumn.ValueType = typeof(ReadAccess);

这是关于DataGridView的由设计师生成的代码:

this.rolesDataGridView.AutoGenerateColumns = false;
this.rolesDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.TableNameDataGridViewTextBoxColumn,
this.ReadDataGridViewComboBoxColumn,
this.WriteDataGridViewComboBoxColumn,
this.ReadCodeDataGridViewComboBoxColumn,
this.ProcessDataGridViewCheckBoxColumn,
this.AdministrateDataGridViewCheckBoxColumn});
this.rolesDataGridView.DataSource = this.bsTablePermissions;

最后,在InitializeComponent();之后,我设置了DataGridView的DataSource:

this.rolesDataGridView.DataSource = this.RoleTablePermissions;  // a bindingsource list

你是否已经执行了 this.Controls.Add(ReadDataGridViewComboBoxColumn) 或类似的操作? - George Stocker
@George:好的,没问题...但是当我运行这个项目时,下拉框被冻结了,我无法打开它的列表... - Dr TJ
除了这个之外,还有更多的代码来实例化DataGridView吗? - George Stocker
只是设计师生成的代码...让我把它们放在这里... - Dr TJ
尝试订阅DataGridView.DataError事件并检查是否存在错误。 - jfs
4个回答

23

我遇到过很多次的问题是:DataGridViewComboBoxColumn不知道如何解决枚举的字符串表示和整数值之间的差异。即使您将ValueType设置为枚举类型,DataGridView仍会尝试将单元格的值设置为底层int值,这就是为什么在数据绑定期间会引发FormatException异常的原因。

我发现克服这个问题的唯一方法(除了子类化单元格类型)是将DataGridViewComboBoxColumn绑定到一个数据源上,该数据源将字符串值与整数值分离。您可以使用匿名类型来实现此目的:

ReadDataGridViewComboBoxColumn.ValueType = typeof(ReadAccess);
ReadDataGridViewComboBoxColumn.ValueMember = "Value";
ReadDataGridViewComboBoxColumn.DisplayMember = "Display";
ReadDataGridViewComboBoxColumn.DataSource = new ReadAccess[]
    { ReadAccess.None, ReadAccess.Allowed }
    .Select(value => new { Display=value.ToString(), Value=(int)value })
    .ToList();

通过这种方式,DataGridView 知道如何将单元格的值与其格式化的值相关联。


@Bradley:我仍然遇到问题...组合框仍然被冻结,我无法打开列表,而且我还收到了“格式异常”的错误信息... - Dr TJ
@Dr TJ:你的“DataGridView”中的其他列是否可能会引起问题,既然你已经解决了这一个?在“DataError”事件的处理程序中检查“ColumnIndex”属性。 - Bradley Smith
@Bradley:我按照你说的做了,错误在所有包含组合框的列上... - Dr TJ
@Dr TJ:我不知道为什么它不起作用...检查一个受影响的单元格的“Value”(在事件处理程序中)- 它设置为枚举值还是“int”? 在所有情况下,当我尝试时它都是“int”。 - Bradley Smith
@Bradley,是的,这是一个Int32值...但我能用它做什么? - Dr TJ
DataGridView 应该通过引用列的 ValueMember 属性,自动查找与整数值对应的枚举值。你确定每个 DataGridViewComboBoxColumnDataSource 属性已设置为我在答案中概述的匿名对象列表吗?如果将其添加到 Items 集合中,它是无法正常工作的。 - Bradley Smith

8

在Bradly Smith提供的答案基础上,我们可以使用以下代码轻松获取所有枚举值(而不是逐个命名):

    ReadDataGridViewComboBoxColumn.DataSource =
        new List<ReadAccess>((ReadAccess[]) Enum.GetValues(typeof(ReadAccess)))
        .Select(value => new { Display=value.ToString(), Value=(int)value })
        .ToList();

2

不应将枚举值转换为整数。如果出现“无效值”错误,请使用以下代码:

ReadDataGridViewComboBoxColumn.DataSource = new ReadAccess[]
{ ReadAccess.None, ReadAccess.Allowed }
.Select(value => new { Display=value.ToString(), Value=value })
.ToList();

0
一个对已接受答案的改进: 没有必要手动将枚举成员作为数组输入。相反,您可以使用System.Enum.GetValues(typeof(ReadAccess))。此外,您可以使用来自字典的List(字典不被接受为数据源)而不是匿名类型列表:
ReadDataGridViewComboBoxColumn.DataSource= System.Enum.GetValues(typeof(ReadAccess))
  .Cast<Enum>.ToDictionary<string, Enum>((e) => e.ToString(), (e) =>  e).ToList;

或者直接返回一个 KeyValuePair 列表

ReadDataGridViewComboBoxColumn.DataSource = System.Enum.GetValues(typeof(ReadAccess))
  .Cast<Enum>.Select((value) => new KeyValuePair<string, enum>(value.ToString(), (value)));

仍然必要(但 DisplayMember 现在是 "Key"):

 ReadDataGridViewComboBoxColumn.ValueType = typeof(ReadAccess);
 ReadDataGridViewComboBoxColumn.ValueMember = "Value";
 ReadDataGridViewComboBoxColumn.DisplayMember = "Key";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接