2009-12-10 12 views
5

Sto scrivendo un'applicazione GUI in cui è necessario abilitare le proprietà di modifica di oggetti arbitrari (i loro tipi sono noti solo in fase di esecuzione).PropertyGrid e tipi dinamici di oggetti

Ho deciso di utilizzare il controllo PropertyGrid per abilitare questa funzionalità. ho creato la seguente classe:

[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; } 
    } 
} 

Quando ricevo un'istanza di un oggetto che ho bisogno di modificare, creo un wrapper per esso e impostarlo come l'oggetto selezionato:

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

Ma io ho incontrato il seguente problema: il precedente funziona come previsto solo quando il tipo di oggetto è un tipo personalizzato (cioè una classe che ho definito da me stesso, o un tipo complesso incorporato) ma non quando obj è un primitivo.

Per esempio, se mi definiscono:

[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; } 
    } 
} 

e da fare:

poi tutto funziona si gonfiano. D'altra parte, quando eseguo il seguente:

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

allora posso vedere il valore "1" nella griglia (e non è in scala di grigi), ma non riesco a modificare il valore. Ho notato che se modifico il tipo di proprietà "Valore" di Wrapper su int e rimuovi l'attributo TypeConverter, funziona. Ho lo stesso comportamento per altri tipi e stringhe primitivi.

Qual è il problema?

Grazie in anticipo!

risposta

5

Se si imposta ExpandableObjectConverter alla proprietà Value, non sarà modificabile e questo è normale perché CanConvertFrom tornerà falso. SE si rimuove il convertitore di tipi, PropertyGrid utilizzerà il TypeConverter generico e si sarà di nuovo nello stesso caso. Quindi la soluzione alternativa è collegare un TypeConverter più intelligente che fungerà da wrapper per il TypeConverter corretto. Ecco uno sporco (non avevo molto tempo, è necessario completare come necessario in quanto ho appena implementato la parte 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); 
    } 
} 

fatemi sapere se avete bisogno di perfezionare qualcosa.

Nicolas

+0

Grazie mille, che ha fatto il trucco! :) – Marina

+0

perché questa linea 'parentConverter.GetProperties (context.Instance);' restituire null? –

0

Rimuovere il "TypeConverter" dalla proprietà "Valore", il PropertyGrid leggerà la la "TypConverter" dal typeo di valore che è in proprietà.

+1

ho provato, quando faccio questa griglia proprietà visualizza correttamente il valore della proprietà, ma in scala di grigi e la modifica è disabilitato (lo fa anche quando obj non è un primitivo) – Marina

+0

Sfortunatamente, MS PropertyGrid non è così intelligente da non aver impostato alcun convertitore sulla proprietà Value. Per il tuo int, non restituirà Int32Converter ma TypeConverter. Lo so perché ho dovuto gestire questo caso in SPG. Guarda la mia risposta per una soluzione. –

+0

Hmm, hai ragione. Fino ad ora ho vissuto in convinzione, che la griglia delle proprietà è così intelligente. Grazie – TcKs

Problemi correlati