2010-11-17 23 views
5

Il semblerait que le contrôle DataGridView peut uniquement se lier aux sources de données qui sont plates (toutes les propriétés sont des types primatifs). Mes données sont hiérarchiques. Par exemple:Recherche d'une solution de contournement pour l'incapacité du contrôle DataGridView à se lier aux données hiérarchiques (OO)

interface INestedObj 
{ 
    string Prop3 { get; } 
} 

interface IParentObj 
{ 
    public string Prop1 { get; } 
    public string Prop2 { get; } 
    public INestedObj NestedObj { get; } 
} 

Étant donné cela, comment se lier à un objet implémentant IParentObj? Finalement, vous êtes confronté à devoir faire quelque chose comme ceci:

grid.Columns["prop1Col"].DataPropertyName = "Prop1"; 
grid.Columns["prop2Col"].DataPropertyName = "Prop2"; 

grid.Columns["prop3Col"].DataPropertyName = "How to display Prop3?"; 

grid.Columns["prop3Col"].DataPropertyName = "NestedObj.Prop3"; // does not work 

Je recherche des conseils et/ou des solutions de rechange.

TIA

Répondre

3

Voici une solution simple qui m'est venue à la fin d'une longue journée. J'ai utilisé une requête et une projection Linq pour créer un type anonyme qui affiche les informations correctes dans DataGridView.

var query = from pt in parentObjCollection 
    select new {Prop1=pt.Prop1, Prop2=pt.Prop2, NestedObj.Prop3=pt.NestedObj.Prop3}; 

je dû fournir la bonne valeur (NestedObj.Prop3) à la propriété DataPropertyName pour obtenir la valeur à afficher dans la grille.

Quand j'ai plus de temps, je vais essayer de mettre en œuvre la solution de Bradley.

+1

C'est une solution beaucoup plus élégante, mais vous devez sacrifier des choses comme la notification de changement (si vos objets l'ont soutenu en premier lieu, je ne sais pas). Une dernière chose que vous pourriez vouloir examiner est l'interface 'ITypedList', qu'une collection peut implémenter afin d'exposer des propriétés personnalisées. C'est un peu moins flakey que la solution 'TypeDescriptorProvider' que j'ai posté, après réflexion. –

2

Vous pouvez probablement ajouter une colonne non consolidé pour « NestedObj.Prop3 » et gérer manuellement sa valeur. Pour obtenir la colonne remplie, gérer l'événement CellFormatting de DataGridView, obtenir le DataBoundItem de la ligne en cours et obtenir le Prop3 à partir de cela. Pour mettre à jour la source de données, gérez l'événement CellValidated pour mettre à jour le DataBoundItem.

Il peut y avoir des événements plus appropriés à utiliser que ceux que j'ai mentionnés, mais vous avez l'idée.

7

Vous pouvez propriétés de INestedObj exposes pour la liaison, mais la solution est très messy.To donner des renseignements généraux, tous les contrôles WinForms qui prennent en charge l'utilisation databinding TypeDescriptor pour déterminer les propriétés existent sur les objets qu'ils se lient à . Par TypeDescriptionProvider et CustomTypeDescriptor, vous pouvez remplacer le comportement par défaut et donc ajouter/masquer les propriétés - dans ce cas, masquer la propriété NestedObj et la remplacer par toutes les propriétés du type imbriqué.

La technique que je vais montrer a 2 (grand-ish) mises en garde:

  1. Puisque vous travaillez avec des interfaces (et non des classes concrètes), vous devez ajouter le descripteur de type personnalisé à runtime.
  2. Le descripteur de type personnalisé doit être capable de créer une instance concrète de IParentObj, il doit donc connaître une telle classe qui a un constructeur par défaut.

(S'il vous plaît excuser le code long)

D'abord, vous avez besoin d'une façon d'envelopper un PropertyDescriptor du type imbriqué afin qu'il puisse être accessible à partir du type parent:

public class InnerPropertyDescriptor : PropertyDescriptor { 
    private PropertyDescriptor innerDescriptor; 

    public InnerPropertyDescriptor(PropertyDescriptor owner, 
     PropertyDescriptor innerDescriptor, Attribute[] attributes) 
     : base(owner.Name + "." + innerDescriptor.Name, attributes) { 
     this.innerDescriptor = innerDescriptor; 
    } 
    public override bool CanResetValue(object component) { 
     return innerDescriptor.CanResetValue(((IParentObj)component).NestedObj); 
    } 
    public override Type ComponentType { 
     get { return innerDescriptor.ComponentType; } 
    } 
    public override object GetValue(object component) { 
     return innerDescriptor.GetValue(((IParentObj)component).NestedObj); 
    } 
    public override bool IsReadOnly { 
     get { return innerDescriptor.IsReadOnly; } 
    } 
    public override Type PropertyType { 
     get { return innerDescriptor.PropertyType; } 
    } 
    public override void ResetValue(object component) { 
     innerDescriptor.ResetValue(((IParentObj)component).NestedObj); 
    } 
    public override void SetValue(object component, object value) { 
     innerDescriptor.SetValue(((IParentObj)component).NestedObj, value); 
    } 
    public override bool ShouldSerializeValue(object component) { 
     return innerDescriptor.ShouldSerializeValue(
      ((IParentObj)component).NestedObj 
     ); 
    } 
} 

Ensuite, vous devez écrire un descripteur de type personnalisé qui expose les propriétés du type imbriqué:

... d, alors vous avez besoin d'un moyen d'exposer le descripteur de ci-dessus:

public class ParentObjDescriptionProvider : TypeDescriptionProvider { 
    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, 
     object instance) { 
     return new ParentObjDescriptor(); 
    } 
} 

Enfin, lors de l'exécution (avant vous liez à la DataGridView), vous devez associer le fournisseur de description de type avec l'interface IParentObj. Vous ne pouvez pas faire cela à la compilation car TypeDescriptionProviderAttribute ne peut pas être placé sur les interfaces ...

TypeDescriptor.AddProvider(new ParentObjDescriptionProvider(), typeof(IParentObj)); 

J'ai testé cela en liant un DataGridView à un IParentObj[] et faible et voici, il crée des colonnes pour Prop1, Prop2 et NestedObj.Prop3.

Vous devez vous demander, cependant ... cela vaut-il vraiment tous ces efforts?

+0

Wow, merci Bradley. Vous obtenez le trophée d'exhaustivité. La nuit dernière, j'ai été en mesure d'élaborer une solution différente (plus simple ???) que je publierai actuellement. –