2009-12-10 258 views
5

我正在寫一個GUI應用程序,我需要啓用任意對象的編輯屬性(它們的類型只在運行時才知道)。PropertyGrid和動態類型的對象

我決定使用PropertyGrid控件來啓用此功能。 我創建了以下類:

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

當我得到一個對象,我需要編輯的實例,我創建一個包裝它,並將其設置爲選擇對象:

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

但我已經遇到了以下問題 - 只有當obj的類型是某種自定義類型(即我自己定義的類或內置的複雜類型)時,上述工作纔會如預期的那樣,但當obj是原語時,則不會。

例如,如果我定義:

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

,做:

然後一切正常膨脹。在另一方面,當我執行以下操作:

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

然後,我可以看到在網格中的值「1」(這不是灰度化),但我不能編輯值。我注意到,如果我將Wrapper的「Value」屬性的類型更改爲int並刪除TypeConverter屬性,它將起作用。 對於其他基元類型和字符串,我得到相同的行爲。

什麼問題?

在此先感謝!

回答

5

如果您將ExpandableObjectConverter設置爲您的Value屬性,它將不可編輯,這是正常的,因爲CanConvertFrom將返回false。如果您刪除了類型轉換器,那麼PropertyGrid將使用泛型TypeConverter,並且您再次處於相同的情況。所以解決方法是附加一個更智能的TypeConverter,它將作爲正確的TypeConverter的包裝。這裏是一葷一(我沒有太多的時間,因爲必要的,因爲我剛剛實施的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); 
    } 
} 

讓我知道如果你需要微調的東西。

尼古拉斯

+0

非常感謝,這是訣竅! :) – Marina 2009-12-11 22:15:32

+0

爲什麼這行'parentConverter.GetProperties(context.Instance);'返回null? – 2013-04-11 08:18:20

0

從屬性「Value」中移除「TypeConverter」,propertygrid將從屬性中的typeo值中讀取「TypConverter」。

+1

我嘗試了,當我做此屬性網格正確顯示屬性的值,但灰度縮放和編輯被禁用(它這樣做,即使當物鏡不是原始) – Marina 2009-12-10 23:56:51

+0

不幸的是, MS PropertyGrid不是那種智能hwne,你沒有爲你的Value屬性設置轉換器。對於你的int,它不會返回Int32Converter而是TypeConverter。我知道這是因爲我必須在SPG中處理這種情況。請參閱我的解決方法。 – 2009-12-11 01:50:17

+0

嗯,你是對的。到現在爲止,我堅信,房地產網格非常聰明。謝謝 – TcKs 2009-12-11 10:23:15