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:
- Puisque vous travaillez avec des interfaces (et non des classes concrètes), vous devez ajouter le descripteur de type personnalisé à runtime.
- 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?
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. –