2009-03-10 10 views
4

J'essaye de lier un DataGridViewComboBoxColumn à une instance de Foo, mais quand je place une valeur sur la grille j'ai un ArgumentException qui me dit que je ne peux pas convertir de String en Foo.Comment lier un DataGridViewComboBoxColumn à un objet?

var data = (from item in someTable 
      select new { Foo = item.foo, Bar = item.Bar }).ToList(); 
grid.DataSource = data; 
column.DataPropertyName = "Foo"; 
column.DataSource = (from foo in Foo select foo).ToList(); //foo is an instance of Foo 
column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance 

Ai-je raté quelque chose? est-il possible de se connecter à un objet complexe?

MISE À JOUR:

I mis en œuvre un TypeConverter et overrided CanConvertFrom, CanConvertTo, ConvertTo, ConvertFrom. Maintenant, je reçois

FormatException: La valeur DataGridViewComboBoxCell n'est pas valide

Toutes les idées?

Répondre

6

Il vous manque une pièce possible.

column.DataPropertyName = "Foo"; 
column.DisplayMember = "SomeNameField"; 
column.ValueMember = "Bar"; // must do this, empty string causes it to be 
          // of type string, basically the display value 
          // probably a bug in .NET 
column.DataSource = from foo in Foo select foo; 
grid.DataSource = data; 

MISE À JOUR:

En fait, après avoir lu votre question, je pense que vous êtes face à ce bogue noté. Il n'y a malheureusement aucun moyen de le faire renvoyer l'objet lié sans utiliser un TypeDescriptor/TypeConverter/BindingSource personnalisé.

Réponse pour la liaison à un objet complexe. Non par défaut J'en ai écrit un très bon pour mon projet actuel. Cela implique de créer un TypeDescriptor/TypeConverter/BindingSource personnalisé qui renvoie toutes les propriétés imbriquées. Un autre 'bug', vous ne pouvez pas utiliser '.' pour un séparateur de membre, j'ai dû recourir à ':' à la place. Le DataGridViewComboBoxColumn doit toujours avoir toutes les valeurs possibles dans la liste des éléments de la liste déroulante ou il lancera "FormatException: la valeur de DataGridViewComboBoxCell n'est pas valide"

+0

Comment créer un TypeConverter? – albertein

+0

Vous héritez de TypeConverter et remplacez les méthodes GetProperties/GetPropertiesSupported. Appliquez ensuite le type à TypeConverterAttribute sur le type de cible souhaité. La zone de sujet est très grande. Google pour plus de direction. – leppie

+0

J'ai mis en œuvre un TypeConverter et substitué CanConvertTo, CanConvertFrom, ConvertTo et ConvertFrom, maintenant j'obtiens l'erreur "FormatException: La valeur de DataGridViewComboBoxCell n'est pas valide" après avoir réglé la valeur – albertein

6

Si vous essayez de récupérer les valeurs sélectionnées dans une colonne de liste déroulante, vous pouvez gérer l'événement DataGridView CellParsing et obtenir l'élément sélectionné à partir de DataGridView.EditingControl car il sera défini pour modifier le contrôle à partir de la colonne modifiée. Voici un exemple:

private void dataGridView1_CellParsing(object sender, 
DataGridViewCellParsingEventArgs e) { 
    if (dataGridView1.CurrentCell.OwningColumn is DataGridViewComboBoxColumn) { 
     DataGridViewComboBoxEditingControl editingControl = 
       (DataGridViewComboBoxEditingControl)dataGridView1.EditingControl; 
     e.Value = editingControl.SelectedItem; 
     e.ParsingApplied = true; 
    } 
} 

Vous pouvez également personnaliser la façon dont vos objets sont montrent sur chaque cellule en manipulant la cellule mise en forme de l'événement, voici un code qui affiche toString pour tout objet ou de l'interface.

private void dataGridView1_CellFormatting(object sender, 
    DataGridViewCellFormattingEventArgs e) { 
     if (e.Value != null) { 
      e.Value = e.Value.ToString(); 
      e.FormattingApplied = true; 
     } 
    } 

gère ce deux événements devraient être assez pour les données d'exposition et modifier dans un objet bussiness et ses Easer puis des convertisseurs de type d'écriture. Pour ce travail défini, vous DataGridView et vous colonne combobox comme suit:

var data = (from item in someTable 
     select new { Foo = item.foo, Bar = item.Bar }).ToList(); 
grid.DataSource = data; 
column.DataPropertyName = "Foo"; 
column.DataSource = (from foo in Foo select foo).ToList(); 

Pas DisplayMember ou ValueMember propriété doivent être configurés, assurez-vous que votre liste de sources de données combobox a toutes les valeurs possibles pour Foo.

Espérons que cela aide.

+0

Incroyable! Merci beaucoup!!!! –

+0

Drôle, c'est la seule chose qui a fait le travail pour moi, et en même temps le plus facile. Je ne peux pas voir comment il a obtenu seulement 4 voix et était difficile à trouver. Toute idée de pourquoi l'implémentation par défaut essaye de convertir la représentation de chaîne de l'élément sélectionné au type de source de données (qui échoue pour les types personnalisés et difficile à personnaliser avec un convertisseur personnalisé), au lieu de simplement paramétrer l'élément sélectionné. !), comme la combo standard? –

2

Je continuais constamment le même problème jusqu'à ce que je découvre que vous ne pouvez pas définir le DisplayMember du DataGridViewComboBoxCell sans régler le ValueMember aussi.
De même, en définissant le ValueMember et non le DisplayMember est également un échec, vous devez définir aucun ou les deux.

Votre modèle est Foo, et vous voulez certainement que la valeur de la zone de liste déroulante soit l'élément lui-même. Pour ce faire, la manière la plus simple est aussi de créer une propriété dans votre foo, en retournant elle-même.

public class Foo 
{ 
    ... 
    public Foo This { get {return this; } } 
} 

Ensuite, les liaisons devient:

column.DataPropertyName = "Foo"; 
column.DataSource = (from foo in Foo select foo).ToList(); //foo is an instance of Foo 
column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance 
column.ValueMember = "This"; 

Cela devrait fonctionner, et la valeur de la cellule doit être de type Foo comme prévu.

Une référence intéressante: Problems with the DataGridViewComboBoxColumn

Cependant, le DataGridViewComboBoxColumn ne fonctionne pas comme ça, bien qu'il affiche la valeur ToString si vous ne définissez pas le DisplayMember, quelque chose se passe mal en interne quand il essaie de regarder jusqu'à SelectedItem, vous devez définir DisplayMember à une propriété publique de votre classe. Pire encore, le comportement par défaut si vous n'avez pas définir la propriété ValueMember est de retourner le DisplayMember, il n'y a aucun moyen d'obtenir l'élément réel lui-même . Le seul travail consiste à ajouter une propriété à votre classe qui se retourne et définir cette propriété à l'utilisateur de la valeur. Bien sûr, si votre objet n'est pas quelque chose que vous pouvez modifier (comme l'une des classes de structure), vous devrez composer ensemble un objet conteneur contenant une référence à votre élément.

4

En fait, vous pouvez utiliser un type complexe dans DataGridViewComboBoxColumn. EX:

 DataGridViewComboBoxColumn.DataPropertyName = "ValueMode"; 
     DataGridViewComboBoxColumn.DisplayMember = "Label"; 
     DataGridViewComboBoxColumn.ValueMember = "Self"; * 
     DataGridViewComboBoxColumn.ValueType = typeof(ValueModeItem); 
  • 'Self' est
public ValueModeItem Self 
    { 
     get 
     { 
      return this; 
     } 
    } 

et très important - nécessité de remplacer 'Equals' méthode d'un type complexe - dans mon cas:

public override bool Equals(object obj) 
    { 
     if (obj is ValueModeItem && obj != null) 
     { 
      if (...) 
       return true; 
     } 
     return false; 
    } 
Questions connexes