DataGridView linked to DataTable with Combobox column based on enum

RosieC picture RosieC · Jul 31, 2013 · Viewed 13.5k times · Source

Having spent a lot of yesterday searching on this one I have to give up.

I have a DataGridView linked to a Datatable. One of the columns is an enum and I want that to show as a Combobox column.

I found this link Create drop down list options from enum in a DataGridView which has an answer of using the following...

    DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
    col.Name = "My Enum Column";
    col.DataSource = Enum.GetValues(typeof(MyEnum));
    col.ValueType = typeof(MyEnum);
    dataGridView1.Columns.Add(col);

I've tried that but when the user creates a new record, chooses an option from the drop down (the correct options show) then moves off the field they get the message "DataGridViewComboBoxCel value is not valid". I've found some solutions in searching that talk about how to trap this error, then do nothing (thus hiding the error) but I want to solve it not just hide it. If the user OK's the message they get it repeat another two times.

I've also seen solutions that loop through the values in the enum and create a datatable containing the int and the string for each one, then using the datatable as a datasource on the combo. I've used a datatable as the source for a combobox in the past when working with a back-end MSSQL database.

Another variant of this is to loop through and write straight into the combo such as this...

    foreach (MyEnum bar in MyEnum.GetValues(typeof(MyEnum)))
    {
        string barName = MyEnum.GetName(typeof(MyEnum), bar);
        MyComboColumn.Items.Add(barName);
    }

such as in the question in this link. How can I add some Enum values to a combobox

MY QUESTION: Can it be made to work using the Enum.GetValues(typeof(MyEnum)); method? The datatable method seems long winded. The looping then using MyComboColumn.Items.Add(barName); is also somewhat long winded and will result in the string version of the enum being recorded in the datatable not the integer (and I would rather it was the integer).

I can't find examples of the Enum.GetValues(typeof(MyEnum)) method where the grid is linked to a datatable. When I search on that I just come across the other methods.

I think the problem is likely to lie in the data type on the underlying table column. I've tried this as an integer, as a string and I've tried not defining it. I can't think what else to try on that type.

Here is my simplified code. (DVG is my DataGridView on the form).

enum EngineType
{
    None = 0,
    EngineType1 = 1,
    EngineType2 = 2
}
public partial class MyClass : Form
{
    DataTable DtTbl;

    public MyClass()
    {
        InitializeComponent();
        CreateTableStructure();
    }

    private void CreateTableStructure()
    {
        DGV.AutoGenerateColumns = false;
        DGV.DataSource = DtTbl;

        DtTbl = new DataTable();

        DtTbl.Columns.Add(new DataColumn("Name", System.Type.GetType("System.String")));
        DataGridViewTextBoxColumn NameCol = new DataGridViewTextBoxColumn();
        NameCol.DataPropertyName = "Name";
        NameCol.HeaderText = "Name";
        DGV.Columns.Add(NameCol);

        DtTbl.Columns.Add(new DataColumn("Engine", System.Type.GetType("System.Int32")));
        DataGridViewComboBoxColumn EngineCol = new DataGridViewComboBoxColumn();
        EngineCol.DataPropertyName = "Engine";
        EngineCol.HeaderText = "Engine";
        //EngineCol.DataSource = EngineType.GetValues(typeof(EngineType));

        foreach (EngineType engine in EngineType.GetValues(typeof(EngineType)))
        {
            string engineName = EngineType.GetName(typeof(EngineType), engine);
            EngineCol.Items.Add(engineName);
        }


        DGV.Columns.Add(EngineCol);

    }
}

Answer

Koryu picture Koryu · Jul 31, 2013

i had this problem myself, here is how i fixed it:

 DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
 col.ValueType = typeof(MyEnum);
 col.ValueMember = "Value";
 col.DisplayMember = "Display";
 colElementtyp.DataSource = new MyEnum[] { MyEnum.Firstenumvalue, MyEnum.Secondenumvalue }
     .Select(value => new { Display = value.ToString(), Value = value })
     .ToList();

the DataGridViewComboBoxCell has to be bound to the enum or integer. I guess the column of your datatable is integer, then it should work.

EDIT:

this should work dynamic:

 System.Array enumarray = Enum.GetValues(typeof(MyEnum)); 
 List<MyEnum> lst = enumarray.OfType<MyEnum>().ToList();
 DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
     col.ValueType = typeof(MyEnum);
     col.ValueMember = "Value";
     col.DisplayMember = "Display";
     colElementtyp.DataSource = lst 
         .Select(value => new { Display = value.ToString(), Value = value })
         .ToList();

shorter:

 DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
 col.ValueType = typeof(MyEnum);
 col.ValueMember = "Value";
 col.DisplayMember = "Display";
 colElementtyp.DataSource = Enum.GetValues(typeof(MyEnum)).OfType<MyEnum>().ToList() 
         .Select(value => new { Display = value.ToString(), Value = value })
         .ToList();