Question

J'essaie de lier un DataGridViewComboBoxColumn à une instance de Foo, mais lorsque je mets une valeur sur la grille, un ArgumentException me dit que je ne peux pas convertir de String en Foo.

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

Est-ce que je manque quelque chose? est-il possible de lier des données à un objet complexe?

UPDATE:

J'ai implémenté un TypeConverter et substitué CanConvertFrom, CanConvertTo, ConvertTo, ConvertFrom. Maintenant, je reçois

  

FormatException: la valeur DataGridViewComboBoxCell n'est pas valide

Des idées?

Était-ce utile?

La solution

Il vous manque un morceau 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 relu votre question, je pense que vous êtes confronté à ce bogue noté. Il n’existe malheureusement aucun moyen de le faire retourner l’objet dépendant sans l’utilisation d’un TypeDescriptor / TypeConverter / BindingSource personnalisé.

Réponse pour la liaison à un objet complexe. Non par défaut J'ai écrit un très bon projet pour mon projet actuel. Cela implique la création d'un TypeDescriptor / TypeConverter / BindingSource personnalisé qui renvoie toutes les propriétés imbriquées. Un autre 'bug', vous ne pouvez pas utiliser '.' pour un membre séparateur, je devais recourir à ':' à la place.

Autres conseils

le DataGridViewComboBoxColumn doit toujours avoir toutes les valeurs possibles dans la liste des éléments de liste déroulante ou il lancera " FormatException: la valeur DataGridViewComboBoxCell n’est pas valide ".

Si vous essayez de récupérer les valeurs choisies 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 le contrôle d'édition à 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 le mode d'affichage de vos objets sur chaque cellule en gérant l'événement de formatage de la cellule. Voici un code qui affiche toString pour tout objet ou interface.

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

Le traitement de ces deux événements devrait être suffisant pour afficher et éditer des données dans un objet bussiness. Il est alors plus facile d'écrire des convertisseurs de type. Pour ce travail, définissez DataGridView et la colonne déroulante 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 ();

Aucune propriété DisplayMember ou ValueMember ne doit être définie, assurez-vous simplement que votre liste de sources de données de liste déroulante contient toutes les valeurs possibles pour Foo.

J'espère que cela vous aidera.

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

Par exemple:

DataGridViewComboBoxColumn.DataPropertyName = "ValueMode";
DataGridViewComboBoxColumn.DisplayMember = "Label";
DataGridViewComboBoxColumn.ValueMember = "Self"; *
DataGridViewComboBoxColumn.ValueType = typeof(ValueModeItem);

Self est:

public ValueModeItem Self
{
    get
    {
        return this;
    }
}

Très important - nécessité de remplacer la méthode 'Equals' d'un type complexe. Dans mon cas:

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

Je rencontrais constamment le même problème jusqu'à ce que je découvre que vous ne pouvez pas définir le DisplayMember du DataGridViewComboBoxCell sans définir également le ValueMember . < br> De la même manière, définir 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 ComboBox soit l’élément lui-même. Pour ce faire, le moyen le plus simple est de créer une propriété dans votre toto, en le retournant lui-même.

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

La liaison devient alors:

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 devrait être de type Foo comme prévu.

Une référence intéressante: Problèmes liés à DataGridViewComboBoxColumn

  

Cependant, le DataGridViewComboBoxColumn ne fonctionne pas comme ça,   bien qu’il affiche la valeur ToString si vous ne définissez pas le paramètre   DisplayMember, quelque chose se passe en interne quand il essaie de regarder   l’élément SelectedItem, vous devez définir DisplayMember sur public   propriété de votre classe. Pire encore, le comportement par défaut si vous ne le faites pas   définir la propriété ValueMember est de retourner le DisplayMember, il y a   aucun moyen d'obtenir l'objet réel lui-même. La seule solution consiste à ajouter un   propriété à votre classe qui se retourne et définit cette propriété à   le ValueMember. Bien sûr, si votre article n'est pas quelque chose que vous pouvez   pour changer (comme l’une des classes du framework), vous devrez tergiverser   ensemble un objet conteneur contenant une référence à votre élément.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top