首页 文章

使用ComboBox将DataGridView绑定到DataTable不起作用

提问于
浏览
1

我正在尝试创建绑定到DataTable的DataGridView,其中一列是ComboBox . 代码运行但绑定后我得到以下错误(不是绑定数据时):System.ArgumentException:DataGridViewComboBoxCell值无效 .

在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创建如下:

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做错 .

可能是什么问题呢?

1 回答

  • 4

    似乎您缺少的步骤是为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 ,注意Structure列类型是 structureType (或经常是 int ) . DataTable 将存储数据,而不是 DataGridViewComboBoxCell 元素 . 在数据来自数据库的情况下,该列将是 int ,因为 structureType 不是已知类型 .

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

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

    添加CBO列时重要的是设置 ValueMemberDsiplayMember 属性以提供值< - >名称转换和 DataPropertyName ,以便它知道在 DataTable 中存储所选值的位置 .

    enter image description here

相关问题