【问题标题】:PropertyGrid and Dynamic Types of ObjectsPropertyGrid 和对象的动态类型
【发布时间】:2009-12-10 23:28:13
【问题描述】:

我正在编写一个 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 并将它设置为选定的对象:

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 属性,它就可以工作。 对于其他原始类型和字符串,我得到相同的行为。

有什么问题?

提前致谢!

【问题讨论】:

    标签: c# wpf controls propertygrid


    【解决方案1】:

    如果您将 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);
        }
    }
    

    如果您需要微调,请告诉我。

    尼古拉斯

    【讨论】:

    • 为什么parentConverter.GetProperties(context.Instance);这行返回null?
    【解决方案2】:

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

    【讨论】:

    • 我试过了,当我这样做时,属性网格会正确显示属性的值,但是灰度和编辑被禁用(即使 obj 不是原始对象也会这样做)
    • 不幸的是,MS PropertyGrid 并不是您为您的 Value 属性设置任何转换器的聪明方法。对于您的 int,它不会返回 Int32Converter,而是返回 TypeConverter。我知道是因为我必须在 SPG 处理这个案子。请参阅我的解决方法。
    • 嗯,你是对的。到现在为止,我一直坚信,该物业网格是如此聪明。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    相关资源
    最近更新 更多