2

I've found several topics with a similar issue but the contents seemed slightly different and I have not been able to solve my problem as a result.

In my application I have DataTable that contains 4 columns:

  • UInt16
  • UInt64
  • UInt64
  • A self defined enumeration type consisting of 2 values.

In order to display the values of this DataTable I created a DataGridView and set this table as the datasource. So far so good. I wanted the enumeration field column to contain comboboxes instead and ran into the DataGridViewComboBoxColumn type. I had some issues getting it to work but eventualy ended up using the following approach:

// 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

I have created the DataGridViewComboBoxColumn as follows:

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);

Once my application starts I read in data from a text file that get placed into a structure with fields of the 4 datatypes mentioned above. I then add these fields to the DataTable as follows:

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);

on startup the DataError event gets called repeatedly. The contents of the cells do get filled properly however. (I see this after clicking away the error a couple of times) Disabling the DataError event (assigning an empty handler for example) is something I prefer to not do.

I think there is some sort of type mismatch somehow. (maybe the enum type and a string for display?) This is however only a guess. The dataTable column and the datagridview column both have the type set to the enumeration.

I hope someone can point me in the right direction.

Thanks in advance!

Arnold4107176
  • 175
  • 2
  • 4
  • 7

3 Answers3

1

Instead of adding and removing the last column, how about listening for the ColumnAdded event in the DataGridView then changing the type then:

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;
   } 
}
SwDevMan81
  • 48,814
  • 22
  • 151
  • 184
  • I cannot get your proposed solution to work. An error is given on the last statement: Cannot implicitly convert type 'System.Windows.Forms.DataGridViewComboBoxColumn' to 'System.Windows.Forms.DataGridViewCell' (CS0029) – Arnold4107176 May 03 '12 at 13:28
  • Not sure if relevant, but if i change "cb" with "cb.CellTemplate" on the last line, it compiles but i get a run-time exception. (System.InvalidCastException) with the message: "Value provided for CellTemplate must be of type System.Windows.Forms.DataGridViewTextBoxCell or derive from it. " – Arnold4107176 May 03 '12 at 13:39
  • @Arnold4107176 - Sorry, I just copied your stuff, it should really be a `DataGridViewComboBoxCell`. Let me update it – SwDevMan81 May 03 '12 at 13:48
  • Ive applied the changes but I still receive the InvalidCastException unfortunately. (After double checking to make sure I entered your code correctly) – Arnold4107176 May 03 '12 at 14:06
0

I have managed to find a workaround that suits my needs. The approach is still the same as in my original post. I made gave the enum in the DataTable the name "colMyEnumTypeTable" and the datatype is string instead of MyEnumType. Then I removed this column and added the DataGridViewComboBoxColumn named "colMyEnumType" with DataPropertyName "colMyEnumTypeTable" and also being of type string. I then convert the enumeration values to string when adding them to the data table, and when extracting I use Enum.Parse to retrieve the enum value again. No more DataError calls are made.

-edit- I gave the DataTable and DataGridViewComboBoxColumn different names to ensure that wasn't causing problems. I have now changed them back so they have the same name and it still works.

-edit2- And instead of setting the DataSource property for the comboboxcolumn I added the enum values by adding them to the Items property. (after converted to string)

Arnold4107176
  • 175
  • 2
  • 4
  • 7
0

The reason why assigning the enum directly to the combo box with a datatable gives the 'value is not valid' error is the type difference between the enum in the DataGridViewComboBoxColumn and the integral value in the DataRow (Enums are always stored as their underlying type in a DataRow regardless if the column type is set to the enum type). e.g. if you read back row["Name of the enum column"] after calling row["Name of the enum column"] = mystruct.theEnumValue;
it wouldn't be the enum you had just assigned but its underlying value. This post: DataGridView linked to DataTable with Combobox column based on enum has an alternative solution using a Key-Value DataSource.

Community
  • 1
  • 1
Jeremy Thomas
  • 189
  • 2
  • 4