【问题标题】:Binding DataGridView to DataTable with ComboBox not working使用 ComboBox 将 DataGridView 绑定到 DataTable 不起作用
【发布时间】:2017-01-07 19:25:11
【问题描述】:

我正在尝试创建一个绑定到 DataTable 的 DataGridView,其中一列是 ComboBox。代码运行,但绑定后(不是绑定数据时)出现以下错误:System.ArgumentException: DataGridViewComboBoxCell value is not valid.

在 DataGridView 中,其中一列是 DataGridViewComboBoxColumn,它使用枚举(命名为 structureType)作为源:

// ColumnStructure
// 
this.ColumnStructure.ValueType = typeof(structureType);
this.ColumnStructure.DataSource = Enum.GetValues(typeof(structureType));
this.ColumnStructure.HeaderText = "Structure";
this.ColumnStructure.Name = "ColumnStructure";
this.ColumnStructure.DataPropertyName = "Structure";
//

当我在不使用 DataTable 的情况下填充 DataGridView 时,它工作得很好:

structureType? structure = GetStructure(part);
dgvObjectTypes.Rows.Add(name, type, structure, count);

现在我想改用 DataTable,但无法让它工作。数据表的创建如下:

DataTable table = new DataTable();
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Type", typeof(string));
table.Columns.Add("Structure", typeof(DataGridViewComboBoxCell));
table.Columns.Add("Count", typeof(int));

其他栏效果很好,但我无法让“结构”栏工作。以下是我尝试创建组合框的方式:

var cb = new DataGridViewComboBoxCell();
cb.ValueType = typeof(structureType);
cb.DataSource = Enum.GetValues(typeof(structureType));
cb.Value = (structureType)structure;

之后我只是为表创建行并将表设置为 DataGridView 的数据源:

table.Rows.Add(name, type, cb, count);
dgv.DataSource = table;

我读过很多帖子,其中指出在组合框中使用枚举会导致问题(例如:DataGridView linked to DataTable with Combobox column based on enum),但这里似乎并非如此。我什至尝试使用显式类型的字符串数组,但仍然得到相同的错误。我认为我在 DataGridViewComboBoxCell 上做错了。

可能是什么问题?

【问题讨论】:

    标签: c# .net datagridview datatable datagridviewcombobox


    【解决方案1】:

    您似乎缺少的步骤是为 CBO 提供名称和值。 DataTable可以存储值,DGV可以显示相关名称,但需要您帮忙提供翻译。

    private enum structureType
    { None, Circle, Square, Pyramid}
    ...
    
    dtStruct = new DataTable();
    dtStruct.Columns.Add("Name", typeof(string));
    dtStruct.Columns.Add("Type", typeof(string));
    dtStruct.Columns.Add("Structure", typeof(structureType));
    dtStruct.Columns.Add("Count", typeof(int));
    
    // autogen columns == true
    dgv2.DataSource = dtStruct;
    
    // create DataSource as list of Name-Value pairs from enum
    var cboSrc = Enum.GetNames(typeof(structureType)).
                        Select( x => new {Name = x, 
                                          Value = (int)Enum.Parse(typeof(structureType),x)
                                          }
                               ).ToList();
    
    // replace auto Text col with CBO col
    DataGridViewComboBoxColumn cb = new DataGridViewComboBoxColumn();
    cb.ValueType = typeof(structureType);
    cb.DataSource = cboSrc;
    cb.DisplayMember = "Name";          // important
    cb.ValueMember = "Value";           // important
    cb.HeaderText = "Structure";
    cb.DataPropertyName = "Structure";  // where to store the value
    
    dgv2.Columns.Remove(dgv2.Columns[2]);  // remove txt col
    dgv2.Columns.Add(cb);
    cb.DisplayIndex = 2;
    
    // add data
    dtStruct.Rows.Add("Ziggy", "Foo", structureType.Circle, 6);
    

    第一部分创建DataTable,注意结构列类型是structureType(或者经常是int)。 DataTable 将存储数据,而不是 DataGridViewComboBoxCell 元素。在数据来自数据库的情况下,该列将是 int,因为 structureType 不是已知类型。

    然后从枚举名称和值创建DataSource。这为控件提供了显示名称的方法,同时将值存储在 DataTable 中。

    如果 DGV 设置为自动生成列,您需要将默认的 TextBoxColumn 替换为 ComboBoxColumn。这是在设置DataSource 之后但在添加任何数据之前完成的。当数据来自数据库时(因此通常没有空的类型化表),您可以使用 ColumnAdded 事件将一列换成另一列。

    添加 CBO 列时重要的是设置ValueMemberDsiplayMember 属性以提供值 名称翻译和DataPropertyName,以便它知道将选定值存储在DataTable 中的位置.

    【讨论】:

    • 谢谢!我已经失去了希望。进一步的问题:如果structureType? 为空,是否有一种简单的方法可以将组合框显示为空?这很酷,但我也可以只在枚举中添加“None”。
    • 添加None 是最简单的。
    猜你喜欢
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 2014-04-19
    • 2019-02-12
    • 1970-01-01
    • 2021-05-19
    相关资源
    最近更新 更多