【问题标题】:DataError on DataGridViewComboBoxColumn bound to a DataTable绑定到 DataTable 的 DataGridViewComboBoxColumn 上的 DataError
【发布时间】:2024-01-18 19:10:02
【问题描述】:

我发现几个主题有类似的问题,但内容似乎略有不同,因此我无法解决我的问题。

在我的应用程序中,我有包含 4 列的 DataTable:

  • UInt16
  • UInt64
  • UInt64
  • 由 2 个值组成的自定义枚举类型。

为了显示这个 DataTable 的值,我创建了一个 DataGridView 并将这个表设置为数据源。到目前为止,一切都很好。我希望枚举字段列包含组合框,但遇到了 DataGridViewComboBoxColumn 类型。我在让它工作时遇到了一些问题,但最终使用了以下方法:

// Create the 4 datarows

// Add the datarows to the data table

// Set the data table as the data source for the data grid view

// Remove the column that represents the enumeration

// Add a DataGridViewComboBoxColumn to the DataGridView as replacement

我已按如下方式创建了 DataGridViewComboBoxColumn:

DataGridViewComboBoxColumn cb = new DataGridViewComboBoxColumn();
cb.HeaderText   = "My header text";
cb.ValueType    = typeof(MyEnumType);
cb.DataSource   = Enum.GetValues(typeof(MyEnumType));
cb.FlatStyle    = FlatStyle.System;
cb.Name         = "Name"; //Same name as the DataColumn and the now deleted DataGridViewColumn
cb.DataPropertyName = "Name"; //Same name as the DataColumn and the now deleted DataGridViewColumn
cb.DisplayStyle     = DataGridViewComboBoxDisplayStyle.Nothing;

dataGridView.Columns.Add(cb);

一旦我的应用程序启动,我就从一个文本文件中读取数据,这些数据被放入一个具有上述 4 种数据类型字段的结构中。然后我将这些字段添加到 DataTable 中,如下所示:

DataRow row = dataTable.NewRow();
row["Name of the UInt16 column"]    = mystruct.theUInt16;
row["Name of the UInt64 column"]    = mystruct.theUInt64;
row["Name of the UInt64 column"]    = mystruct.theUInt64_2;
row["Name of the enum column"]      = mystruct.theEnumValue;               
dataTable.Rows.Add(row);

在启动时重复调用 DataError 事件。然而,单元格的内容确实被正确填充。 (我在几次点击错误后看到了这一点)禁用 DataError 事件(例如分配一个空的处理程序)是我不想做的事情。

我认为某种程度上存在某种类型的不匹配。 (也许是枚举类型和一个用于显示的字符串?)但这只是一个猜测。 dataTable 列和 datagridview 列都将类型设置为枚举。

我希望有人能指出我正确的方向。

提前致谢!

【问题讨论】:

    标签: c# data-binding datagridview datatable datasource


    【解决方案1】:

    与其添加和删除最后一列,不如在DataGridView 中监听ColumnAdded 事件然后更改类型:

    dataGridView.ColumnAdded += DataGridViewColumnAdded;
    dataGridView.DataSource = dataTable;
    
    private void DataGridViewColumnAdded(Object sender, DataGridViewColumnEventArgs e) 
    {
       if(e.Column.ValueType == typeof(MyEnumType)) 
       {
          DataGridViewComboBoxCell cb = new DataGridViewComboBoxCell();
          cb.ValueType        = typeof(MyEnumType);
          cb.DataSource       = Enum.GetValues(typeof(MyEnumType));
          cb.FlatStyle        = FlatStyle.System;
          cb.DisplayStyle     = DataGridViewComboBoxDisplayStyle.Nothing;
          e.Column.CellTemplate = cb;
       } 
    }
    

    【讨论】:

    • 我无法让您提出的解决方案发挥作用。最后一条语句报错:Cannot implicitly convert type 'System.Windows.Forms.DataGridViewComboBoxColumn' to 'System.Windows.Forms.DataGridViewCell' (CS0029)
    • 不确定是否相关,但如果我在最后一行用“cb.CellTemplate”更改“cb”,它会编译但我得到一个运行时异常。 (System.InvalidCastException) 并显示消息:“为 CellTemplate 提供的值必须是 System.Windows.Forms.DataGridViewTextBoxCell 类型或派生自它。”
    • @Arnold4107176 - 抱歉,我刚刚复制了你的内容,应该是 DataGridViewComboBoxCell。让我更新一下
    • 我已经应用了更改,但不幸的是我仍然收到 InvalidCastException。 (经过仔细检查以确保我正确输入了您的代码)
    【解决方案2】:

    我已设法找到适合我需要的解决方法。该方法仍然与我原来的帖子相同。我给DataTable中的枚举命名为“colMyEnumTypeTable”,数据类型是字符串而不是MyEnumType。然后我删除了这一列,并添加了名为“colMyEnumType”的DataGridViewComboBoxColumn,DataPropertyName为“colMyEnumTypeTable”,也是字符串类型。然后在将枚举值添加到数据表时将它们转换为字符串,并在提取时使用 Enum.Parse 再次检索枚举值。不再进行 DataError 调用。

    -编辑- 我为 DataTable 和 DataGridViewComboBoxColumn 赋予了不同的名称,以确保不会导致问题。我现在已将它们改回来,因此它们具有相同的名称并且仍然有效。

    -edit2- 我没有为组合框列设置 DataSource 属性,而是通过将枚举值添加到 Items 属性来添加枚举值。 (转成字符串后)

    【讨论】:

      【解决方案3】:

      将枚举直接分配给带有数据表的组合框给出“值无效”错误的原因是 DataGridViewComboBoxColumn 中的枚举与 DataRow 中的整数值之间的类型差异(枚举始终存储为其DataRow 中的基础类型,无论列类型是否设置为枚举类型)。 例如如果你回读row["Name of the enum column"] 打电话后row["Name of the enum column"] = mystruct.theEnumValue;
      它不会是您刚刚分配的枚举,而是它的潜在价值。 这篇文章:DataGridView linked to DataTable with Combobox column based on enum 有一个使用键值数据源的替代解决方案。

      【讨论】: