2013-07-31 3 views
3

Проведя много вчерашнего поиска по этому вопросу, я должен отказаться.DataGridView, связанный с DataTable с столбцом Combobox на основе enum

У меня есть DataGridView, связанный с Datatable. Один из столбцов - это перечисление, и я хочу, чтобы это отображалось как столбец 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 недействительно». Я нашел несколько решений в поиске разговоров о том, как заманить эту ошибку, а затем ничего не делать (таким образом, скрывая ошибку), но я хочу решить ее, а не просто скрыть ее. Если пользователь в порядке, то сообщение, которое они получили, повторяется еще два раза.

Я также видел решения, которые проходят через значения в перечислении и создают datatable, содержащие int и строку для каждого, а затем используют datatable в качестве источника данных в комбо. Я использовал datatable как источник для combobox в прошлом при работе с базой данных 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); также немного длиннее, и приведет к тому, что строковая версия перечисления будет записана в datatable, а не целое число (и я предпочел бы это целое число).

Я не могу найти примеры метода Enum.GetValues ​​(typeof (MyEnum)), где сетка привязана к datatable. Когда я нахожусь на этом, я просто сталкиваюсь с другими методами.

Я думаю, что проблема, скорее всего, будет заключаться в типе данных в базовом столбце таблицы. Я пробовал это как целое число, как строку, и я пытался не определять его. Я не могу думать, что еще попробовать по этому типу.

Вот мой упрощенный код. (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); 

    } 
} 
+0

Забыла сказать, что я получаю ту же ошибку в первом решении, если я пытаюсь добавить записи в DataTable программно, а также когда пользователь пытается и использует combobox, чтобы выбрать допустимую запись. – RosieC

ответ

1

Я отказался делать это связывая перечисление непосредственно к Combox. Я думал, что Корю решил это, но пока он работал, когда пользователь вводил данные, если я попытался программно добавить строку с допустимым значением для перечисления, он все равно дал ошибку.

Основываясь на моем предыдущем коде, с изменением Корю, я добавил строку, подобную этой.

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

Но, несмотря на отладку, чтобы обеспечить действительное значение, я все еще получил ошибку.

Я решил использовать этот метод, используя метод datatable. Я написал общий метод в моем вспомогательном классе, который возвращает данные для любого перечисления.

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

В то время как это работает, и у меня есть многоразовый способ сделать это снова, он все еще чувствует, как это должно было быть возможным назначением перечисления непосредственно в поле со списком, как что «почти» работы.

Хотелось бы узнать, почему это не работает, но это решение работает как минимум.

+0

просто подсказка, ее более безопасный и рекомендуемый способ установки значений по умолчанию Datatable: 'YourDataTable.Columns [" Engine "]. DefaultValue = EngineType.EngineType1;' – Koryu

+0

Причина, по которой назначение перечисления непосредственно в поле со списком с помощью datatable дает ошибку «значение недействительно» - это разность типов между перечислением в DataGridViewComboBoxColumn и интегральное значение в DataRow (перечисления всегда сохраняются в качестве базового типа в DataRow независимо от того, установлен ли тип столбца на тип перечисления) , Если DataTable не использовался, он будет работать нормально. –

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 должен быть связан с перечислением или целым числом. Я думаю, столбец вашего datatable целочисленный, тогда он должен работать.

EDIT:

это должно работать динамическая:

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

Спасибо, я подумал, что, возможно, мне придется заполнить ValueMember и DisplayMember, но понятия не имею, как это сделать. Моя проблема с этим решением заключается в том, что я могу захотеть добавить дополнительные значения в перечисление в будущем и не хочу помнить, чтобы изменить его здесь. Я знаю, что забуду :( – RosieC

+0

Я вижу, его кулер, если он работает динамически. Check my edit :) – Koryu

+0

Я думал, что решил (используя последнее решение), но пока он работает, когда пользователь вводит данные, если Я пытаюсь и программно добавить строку с допустимым значением для перечисления, она все равно дает ошибку. Основываясь на моем предыдущем коде, с вашим изменением выше, я добавляю строку, подобную этой. private void CreateDefaultRows() { DataRow Row = DtTbl.NewRow(); Строка ["Name"] = "FIN"; Строка ["Engine"] = EngineType.EngineType1; DtTbl.Rows.Add (строка); DGV.DataSource = DtTbl; } – RosieC

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; 
} 
+0

Спасибо, хорошая модификация :) – RosieC

Смежные вопросы