2016-08-31 3 views
0

Je suis en train de créer un DataGridView lié à un DataTable où une colonne est une zone de liste déroulante. Le code s'exécute mais j'obtiens l'erreur suivante après la liaison (pas lorsque les données sont liées): System.ArgumentException: la valeur DataGridViewComboBoxCell n'est pas valide.Liaison DataGridView à DataTable avec ComboBox ne fonctionne pas

Dans le DataGridView une des colonnes est un DataGridViewComboBoxColumn qui utilise un ENUM (nommé StructureType) comme il est source:

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

Quand je alimenter le DataGridView sans utiliser un DataTable, il fonctionne très bien:

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

Maintenant, je voudrais utiliser un DataTable à la place, mais je ne peux pas le faire fonctionner. Le DataTable est créé comme suit:

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

D'autres colonnes fonctionnent très bien, mais je ne peux pas obtenir la colonne « Structure » fonctionne. Voici comment j'ai essayé de créer le combobox:

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

Après que je viens de créer les lignes de la table et et mettre la table en tant que source de données pour le DataGridView:

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

J'ai lu beaucoup de messages où il a été déclaré que l'utilisation d'énumérations dans les comboboxes pose des problèmes (par exemple: DataGridView linked to DataTable with Combobox column based on enum), mais cela ne semble pas être le cas ici. J'ai même essayé d'utiliser des tableaux de chaînes explicitement typés mais j'ai toujours la même erreur. Je pense que je fais quelque chose de mal avec le DataGridViewComboBoxCell.

Quel pourrait être le problème?

Répondre

3

Il semble que l'étape qui vous manque soit de fournir les noms et les valeurs de l'OCB. Le DataTable peut stocker la valeur, et la DGV peut afficher le nom associé, mais vous devez aider à fournir la traduction.

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

La première partie crée le DataTable, notez que le type de colonne de structure est structureType (ou souvent int). Le DataTable va stocker des données, pas DataGridViewComboBoxCell éléments. Dans les cas où les données proviennent d'une base de données, cette colonne serait int puisque structureType ne serait pas un type connu. Un DataSource est ensuite créé à partir des noms et des valeurs d'énumération. Cela fournit les moyens pour que le contrôle affiche le nom, mais stocke la valeur dans le DataTable. Si la DGV est définie pour générer automatiquement des colonnes, vous devrez remplacer la valeur par défaut TextBoxColumn par une ComboBoxColumn. Ceci est fait après que le DataSource a été défini, mais avant que des données ne soient ajoutées. Lorsque les données proviennent d'une base de données (et qu'il n'y a donc généralement pas de table typée vide), vous pouvez utiliser l'événement ColumnAdded pour échanger une colonne contre une autre.

La chose importante lors de l'ajout de la colonne CBO est de définir les propriétés ValueMember et DsiplayMember pour fournir la valeur < -> traduction de noms et DataPropertyName il sait où stocker la valeur sélectionnée dans le DataTable.

enter image description here

+0

Merci! J'avais déjà perdu espoir. Autre question: Serait-il un moyen facile de définir l'affichage de la zone de liste déroulante vide si 'structureType?' Serait null? Ce serait cool, mais je pourrais aussi aller avec juste "None" ajouté à l'énumération. – JayByte

+0

L'ajout d'un 'None' serait le plus simple. – Plutonix