PropertyGrid和动态对象类型

时间:2009-12-10 23:28:13

标签: c# wpf controls propertygrid

我正在编写一个GUI应用程序,我需要启用任意对象的编辑属性(它们的类型仅在运行时才知道)。

我决定使用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; }
    }
}

并做:

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

然后一切都运转起来。另一方面,当我执行以下操作时:

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

然后我可以在网格中看到值“1”(并且它不是灰度)但我无法编辑该值。我注意到如果我将Wrapper的“Value”属性的类型更改为int并删除TypeConverter属性,它就可以工作。 我对其他原始类型和字符串有相同的行为。

有什么问题?

提前致谢!

2 个答案:

答案 0 :(得分: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);
    }
}

如果您需要微调某些内容,请告诉我。

尼古拉斯

答案 1 :(得分:0)

从属性“Value”中删除“TypeConverter”,propertygrid将从属性中的typeo读取“TypConverter”。