2009-12-10 3 views
5

J'écris une application graphique dans laquelle je dois activer les propriétés d'édition d'objets arbitraires (leurs types sont uniquement connus au moment de l'exécution).Types d'objets PropertyGrid et dynamiques

J'ai décidé d'utiliser le contrôle PropertyGrid pour activer cette fonctionnalité. J'ai créé la classe suivante:

[TypeConverter(typeof(ExpandableObjectConverter))] 
[DefaultPropertyAttribute("Value")] 
public class Wrapper 
{ 
    public Wrapper(object val) 
    { 
     m_Value = val; 
    } 

    private object m_Value; 

    [NotifyParentPropertyAttribute(true)] 
    [TypeConverter(typeof(ExpandableObjectConverter))] 
    public object Value 
    { 
     get { return m_Value; } 
     set { m_Value = value; } 
    } 
} 

Quand je reçois une instance d'un objet que je dois modifier, créer un wrapper pour et le définir comme l'objet sélectionné:

Wrapper wrap = new Wrapper(obj); 
propertyGrid.SelectedObject = wrap; 

Mais je Le problème ci-dessus ne fonctionne que lorsque le type d'obj est un type personnalisé (c'est-à-dire une classe que j'ai définie moi-même, ou un type complexe construit) mais pas quand obj est une primitive.

Par exemple, si je définis:

[TypeConverter(typeof(ExpandableObjectConverter))] 
public class SomeClass 
{ 
    public SomeClass() 
    { 
     a = 1; 
     b = 2; 
    } 

    public SomeClass(int a, int b) 
    { 
     this.a = a; 
     this.b = b; 
    } 

    private int a; 

    [NotifyParentPropertyAttribute(true)] 
    public int A 
    { 
     get { return a; } 
     set { a = value; } 
    } 

    private int b; 

    [NotifyParentPropertyAttribute(true)] 
    public int B 
    { 
     get { return b; } 
     set { b = value; } 
    } 
} 

Et faire:

Puis tout fonctionne houle. D'autre part, quand j'effectuer les opérations suivantes:

int num = 1; 
Wrapper wrap = new Wrapper(num); 
propertyGrid.SelectedObject = wrap; 

Ensuite, je peux voir la valeur « 1 » dans la grille (et il ne grayscaled) mais je ne peux pas modifier la valeur. J'ai remarqué que si je change le type de la propriété "Value" de Wrapper en int et supprime l'attribut TypeConverter, cela fonctionne. J'ai le même comportement pour les autres types et chaînes primitifs.

Quel est le problème?

Merci d'avance!

Répondre

5

Si vous définissez ExpandableObjectConverter sur votre propriété Value, elle ne sera pas modifiable et cela est normal car CanConvertFrom retournera false. Si vous supprimez le convertisseur de type, PropertyGrid utilisera le TypeConverter générique et vous êtes à nouveau dans le même cas. La solution consiste donc à attacher un TypeConverter plus intelligent qui agira comme un wrapper au TypeConverter correct. Voici un sale (j'avais pas beaucoup de temps, vous le compléter au besoin puisque je viens Implémenter la partie de ConvertFrom):

public class MySmartExpandableObjectConverter : ExpandableObjectConverter 
{ 
    TypeConverter actualConverter = null; 

    private void InitConverter(ITypeDescriptorContext context) 
    { 
     if (actualConverter == null) 
     { 
      TypeConverter parentConverter = TypeDescriptor.GetConverter(context.Instance); 
      PropertyDescriptorCollection coll = parentConverter.GetProperties(context.Instance); 
      PropertyDescriptor pd = coll[context.PropertyDescriptor.Name]; 

      if (pd.PropertyType == typeof(object)) 
       actualConverter = TypeDescriptor.GetConverter(pd.GetValue(context.Instance)); 
      else 
       actualConverter = this; 
     } 
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     InitConverter(context); 

     return actualConverter.CanConvertFrom(context, sourceType); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     InitConverter(context); // I guess it is not needed here 

     return actualConverter.ConvertFrom(context, culture, value); 
    } 
} 

Laissez-moi savoir si vous avez besoin de quelque chose finetune.

Nicolas

+0

Merci beaucoup, cela a fait l'affaire! :) – Marina

+0

Pourquoi cette ligne 'parentConverter.GetProperties (context.Instance);' return null? –

0

Enlevez le "TypeConverter" de la propriété "Value", la propriété propertycrid lira le "TypConverter" de typeo de valeur qui est en propriété.

+1

je l'ai essayé, quand je fais la grille de propriétés affiche la valeur de la propriété correctement, mais en niveaux de gris et d'édition est désactivé (il le fait même si obj est pas une primitive) – Marina

+0

Malheureusement, le MS PropertyGrid n'est pas si intelligent que vous n'avez pas défini de convertisseur pour votre propriété Value. Pour votre int, il ne retournera pas Int32Converter mais TypeConverter. Je le sais parce que j'ai dû gérer ce cas dans SPG. VOIS ma réponse pour une solution de contournement. –

+0

Hmm, vous avez raison. Jusqu'à présent, je vivais dans la conviction, que la grille de la propriété est si intelligente. Merci – TcKs