DataGridView基于枚举链接到带有Combobox列的DataTable

时间:2013-07-31 13:50:13

标签: c# datagridview enums datatable datagridviewcombobox

昨天花了很多时间搜索这个,我不得不放弃。

我有一个链接到Datatable的DataGridView。其中一列是enum,我希望它显示为Combobox列。

我发现此链接Create drop down list options from enum in a DataGridView,其答案是使用以下内容...

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

我已尝试过,但是当用户创建新记录时,从下拉列表中选择一个选项(正确的选项显示),然后离开字段,他们会收到消息“DataGridViewComboBoxCel值无效”。我找到了一些解决方案,在搜索中讨论如何捕获此错误,然后什么也不做(从而隐藏错误),但我想解决它而不仅仅是隐藏它。如果用户确定他们收到的消息,则重复两次。

我还看到了遍历枚举值的解决方案,并创建了一个包含int和每个字符串的数据表,然后使用数据表作为组合中的数据源。在使用后端MSSQL数据库时,我曾使用数据表作为组合框的源。

另一种变体是循环并直接写入组合,例如这......

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

例如在此链接中的问题。 How can I add some Enum values to a combobox

我的问题:是否可以使用Enum.GetValues(typeof(MyEnum))工作;方法? 数据表方法看起来很长。然后循环使用MyComboColumn.Items.Add(barName);也有点长篇大论,会导致枚举的字符串版本记录在数据表中而不是整数(我宁愿它是整数)。

我找不到Enum.GetValues(typeof(MyEnum))方法的示例,其中网格链接到数据表。当我搜索时,我只是遇到了其他方法。

我认为问题可能在于基础表列上的数据类型。我已经尝试过这个整数,作为一个字符串,我试过不定义它。我想不出还有什么可以尝试这种类型。

这是我的简化代码。 (DVG是我在表格上的DataGridView)。

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

    }
}

3 个答案:

答案 0 :(得分:2)

我自己有这个问题,这是我如何解决它:

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

DataGridViewComboBoxCell必须绑定到枚举或整数。我猜你的数据表的列是整数,那么它应该可以工作。

修改

这应该是动态的:

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

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

答案 1 :(得分:1)

我放弃了这样做直接将枚举链接到combox。我认为Koryu已经解决了它,但是当用户输入数据时它会起作用,如果我尝试以编程方式添加一行,并且枚举的有效值,它仍会给出错误。

基于我的上述代码,随着Koryu的改变,我添加了这样一行。

private void CreateDefaultRows() 
{
  DataRow Row = DtTbl.NewRow();
  Row["Name"] = "FIN";
  Row["Engine"] = EngineType.EngineType1;
  DtTbl.Rows.Add(Row);
  DGV.DataSource = DtTbl;
}

但是尽管调试以确保有效值,我仍然会收到错误。

我通过使用数据表的方法解决了它。我在我的帮助器类中编写了一个泛型方法,它返回任何枚举的数据表。

    public static DataTable Enum2DataTable<T>()
    {
        DataTable EnumTable = new DataTable();
        EnumTable.Columns.Add(new DataColumn("Value", System.Type.GetType("System.Int32")));
        EnumTable.Columns.Add(new DataColumn("Display", System.Type.GetType("System.String")));
        DataRow EnumRow;
        foreach (T E in Enum.GetValues(typeof(T)))
        {
            EnumRow = EnumTable.NewRow();
            EnumRow["Value"] = E;
            EnumRow["Display"] = E.ToString();
            EnumTable.Rows.Add(EnumRow);
        }

        return EnumTable;
    }

如果我在问题代码中定义组合框列时添加以下行,一切正常,没有其他更改且没有错误。

EngineCol.DataSource = Enum2DataTable<EngineType>();

虽然这有效,并且我有一个可重用的方法来再次执行此操作,但仍然觉得应该可以将枚举直接分配给组合框,因为“几乎”可以正常工作。

很想知道为什么它不起作用,但这种解决方案至少起作用。

答案 2 :(得分:1)

使用RosieC的代码,当枚举的基础类型不是Int32时,我仍然会得到异常。这可以通过一个小修改来修复:

public static DataTable Enum2DataTable<T>()
{
    DataTable EnumTable = new DataTable();
    EnumTable.Columns.Add(new DataColumn("Value", Enum.GetUnderlyingType(typeof(T))));
    EnumTable.Columns.Add(new DataColumn("Display", System.Type.GetType("System.String")));
    DataRow EnumRow;
    foreach (T E in Enum.GetValues(typeof(T)))
    {
        EnumRow = EnumTable.NewRow();
        EnumRow["Value"] = E;
        EnumRow["Display"] = E.ToString();
        EnumTable.Rows.Add(EnumRow);
    }

    return EnumTable;
}