2016-08-31 12 views
0

1つの列がComboBoxであるDataTableにバインドされたDataGridViewを作成しようとしています。コードが実行されますが、バインド後(データがバインドされていないとき)に次のエラーが発生します。System.ArgumentException:DataGridViewComboBoxCellの値が無効です。 DataGridViewのでComboBoxを使用してDataGridViewをDataTableにバインドしない

列の一つは、それが元だとして(structureType命名)列挙型を使用していますDataGridViewComboBoxColumnです:

// ColumnStructure 
// 
this.ColumnStructure.ValueType = typeof(structureType); 
this.ColumnStructure.DataSource = Enum.GetValues(typeof(structureType)); 
this.ColumnStructure.HeaderText = "Structure"; 
this.ColumnStructure.Name = "ColumnStructure"; 
this.ColumnStructure.DataPropertyName = "Structure"; 
// 

私はDataTableのを使用せずにDataGridViewのを移入すると、それだけで正常に動作します:

structureType? structure = GetStructure(part); 
dgvObjectTypes.Rows.Add(name, type, structure, count); 

代わりにDataTableを使用したいが、それを動作させることはできない。 DataTableは次のように作成されます:

DataTable table = new DataTable(); 
table.Columns.Add("Name", typeof(string)); 
table.Columns.Add("Type", typeof(string)); 
table.Columns.Add("Structure", typeof(DataGridViewComboBoxCell)); 
table.Columns.Add("Count", typeof(int)); 

他の列はうまく動作しますが、「構造」列が機能しません。その後

var cb = new DataGridViewComboBoxCell(); 
cb.ValueType = typeof(structureType); 
cb.DataSource = Enum.GetValues(typeof(structureType)); 
cb.Value = (structureType)structure; 

私は、テーブルの行を作成したDataGridViewのデータソースとして、テーブルを設定します:私が読んだ

table.Rows.Add(name, type, cb, count); 
dgv.DataSource = table; 

ここでは、私はコンボボックスを作成しようとした方法ですコンボボックスで列挙型を使用すると問題が発生することが記載されている投稿が多数ありますが(例:DataGridView linked to DataTable with Combobox column based on enumなど)、ここではそうではありません。明示的に型指定された文字列の配列を使用しようとしましたが、同じエラーが発生します。私はDataGridViewComboBoxCellで何か間違っていると思います。

何が問題なのですか?

答えて

3

あなたが欠けているステップのように、CBOの名前と値を提供しているようです。 DataTableには値を格納することができ、DGVは関連する名前を表示できますが、翻訳を提供するのに役立つ必要があります。

private enum structureType 
{ None, Circle, Square, Pyramid} 
... 

dtStruct = new DataTable(); 
dtStruct.Columns.Add("Name", typeof(string)); 
dtStruct.Columns.Add("Type", typeof(string)); 
dtStruct.Columns.Add("Structure", typeof(structureType)); 
dtStruct.Columns.Add("Count", typeof(int)); 

// autogen columns == true 
dgv2.DataSource = dtStruct; 

// create DataSource as list of Name-Value pairs from enum 
var cboSrc = Enum.GetNames(typeof(structureType)). 
        Select(x => new {Name = x, 
             Value = (int)Enum.Parse(typeof(structureType),x) 
             } 
          ).ToList(); 

// replace auto Text col with CBO col 
DataGridViewComboBoxColumn cb = new DataGridViewComboBoxColumn(); 
cb.ValueType = typeof(structureType); 
cb.DataSource = cboSrc; 
cb.DisplayMember = "Name";   // important 
cb.ValueMember = "Value";   // important 
cb.HeaderText = "Structure"; 
cb.DataPropertyName = "Structure"; // where to store the value 

dgv2.Columns.Remove(dgv2.Columns[2]); // remove txt col 
dgv2.Columns.Add(cb); 
cb.DisplayIndex = 2; 

// add data 
dtStruct.Rows.Add("Ziggy", "Foo", structureType.Circle, 6); 

最初の部分はDataTable作成、構造列タイプはstructureType(又はしばしばint)であることに注意してください。 DataTableは、DataGridViewComboBoxCell要素ではなく、データを格納します。データがデータベースから取得された場合、その列はとなります。structureTypeは既知の型ではないためです。

DataSourceは、列挙型の名前と値から作成されます。これにより、コントロールに名前を表示する手段が提供されますが、値はDataTableに格納されます。

DGVが列を自動生成するように設定されている場合は、デフォルトのTextBoxColumnComboBoxColumnに置き換える必要があります。これは、DataSourceが設定された後、データが追加される前に行われます。 DBからデータが取得されると(通常は空の型指定されたテーブルは存在しません)、ColumnAddedイベントを使用してある列を別の列に置き換えることができます。 >名前の変換とDataTableで選択した値を格納する場所をDataPropertyNameはそれが知っている -

CBO列を追加することが重要なことは、価値<を提供するために、ValueMemberDsiplayMemberプロパティを設定することです。

enter image description here

+0

ありがとう!私はすでに希望を失っていた。 さらに質問: 'structureType?'がnullの場合、コンボボックスの表示を空にする簡単な方法がありますか?これはクールかもしれませんが、私は列挙型に "None"を追加しても行けます。 – JayByte

+0

'None'を追加するのが最も簡単です。 – Plutonix

関連する問題