使用ComboBox将DataGridView绑定到DataTable

时间:2016-08-31 09:22:47

标签: c# .net datagridview datatable datagridviewcombobox

我试图创建绑定到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 个答案:

答案 0 :(得分: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,请注意,结构列类型为structureType(或通常为int)。 DataTable将存储数据,而不是DataGridViewComboBoxCell个元素。如果数据来自数据库,则该列将为int,因为structureType不是已知类型。

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

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

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

enter image description here