2009-12-10 18 views
5

Piszę aplikację GUI, w której muszę włączyć edycję właściwości dowolnych obiektów (ich typy są znane tylko w czasie wykonywania).PropertyGrid i dynamiczne typy obiektów

Postanowiłem użyć kontrolki PropertyGrid, aby włączyć tę funkcję. stworzyłem następujące klasy:

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

Kiedy się wystąpienie obiektu muszę zmieniać, tworzę otoki dla niego i ustawić go jako wybranego obiektu:

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

Ale napotkaliśmy następujący problem - powyższe działa zgodnie z oczekiwaniami tylko wtedy, gdy typ obj to jakiś niestandardowy typ (tj. klasa, którą zdefiniowałem samodzielnie lub wbudowany typ złożony), ale nie wtedy, gdy obiekt jest prymitywny.

Na przykład, jeśli określenie:

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

I zrobić:

Potem wszystko działa puchnąć. Z drugiej strony, kiedy należy wykonać następujące czynności:

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

Wtedy widzę wartości „1” w sieci (i to nie grayscaled), ale nie można edytować wartości. Zauważyłem, że jeśli zmienię typ właściwości "Value" Wrappera na int i usunę atrybut TypeConverter, to działa. Otrzymuję to samo zachowanie dla innych pierwotnych typów i ciągów.

Na czym polega problem?

Z góry dziękuję!

Odpowiedz

5

Jeśli ustawisz ExpandableObjectConverter na właściwość Value, nie będzie można go edytować, a to normalne, ponieważ CanConvertFrom zwróci false. JEŚLI usuniesz konwerter typów, właściwość PropertyGrid użyje generycznego TypeConvertera i znów będziesz w tym samym przypadku. Tak więc obejście problemu polega na dołączeniu inteligentniejszego TypeConvertera, który będzie działał jako opakowanie do właściwego TypeConvertera. Oto jeden brudny (nie miałem dużo czasu, można go wypełnić, ile potrzeba, ponieważ po prostu realizowane część 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); 
    } 
} 

Daj mi znać, jeśli trzeba Precyzyjnie dostrój coś.

Nicolas

+0

Wielkie dzięki, to się udało! :) – Marina

+0

Dlaczego ta linia 'parentConverter.GetProperties (context.Instance); zwraca NULL? –

0

Usuń "TypeConverter" z właściwości "Value", właściwość property odczyta "TypConverter" z właściwości wartości, która jest w właściwości.

+1

próbowałem go, gdy robię to siatka nieruchomość wyświetla wartość właściwości poprawnie, ale szaro-skalowane i edytowanie jest wyłączone (robi to nawet wtedy, gdy obj nie jest prymitywny) – Marina

+0

Niestety, MS PropertyGrid nie jest tak inteligentny, że nie ustawiłeś konwertera dla swojej właściwości Value. Dla twojej int nie zwróci Int32Converter, ale TypeConverter. Wiem o tym, ponieważ musiałem obsłużyć tę sprawę w SPG. Zobacz moją odpowiedź na obejście tego problemu. –

+0

Hmm, masz rację. Do tej pory żyłem w przekonaniu, że sieć nieruchomości jest tak inteligentna. Dzięki – TcKs

Powiązane problemy