如何在属性网格中显示动态对象? [英] How to display a dynamic object in property grid?

查看:50
本文介绍了如何在属性网格中显示动态对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义对象类型,必须在 PropertyGrid 中进行

I have a custom object type which has to be editable in PropertyGrid:

public class CustomObjectType
{
    public string Name { get; set; }        
    public List<CustomProperty> Properties {get; set;}
}

其中有一个自定义属性列表:

Which has a list of custom properties:

public class CustomProperty
{
    public string Name { get; set; }
    public string Desc { get; set; }
    public Object DefaultValue { get; set; }    
    Type type;

    public Type Type
    {
        get
        {
            return type;
        }
        set
        {
                type = value;
                DefaultValue = Activator.CreateInstance(value);
        }              
    }
}

这里的主要问题是 PropertyGrid 控件不允许编辑,也没有对属性 DefaultValue 使用适当的编辑工具,该属性事先通过设置 CustomProperty 的字段 Type .

The main problem here is that the PropertyGrid control doesn't allow to edit, nor uses appropriate editing tools for property DefaultValue which is beforehand instantiated by setting value of CustomProperty's field Type.

DefaultValue 的类型仅在运行时已知.

Type of DefaultValue is only known at runtime.

此外,我需要为 CustomProperty 的属性 Type 提供自定义的 TypeConverter ,以显示受支持类型的下拉列表(对于例如, Int String Color MyOwnClass ).

Moreover I need to supply a custom TypeConverter for CustomProperty's property Type to show a drop-down list of supported types (for example, Int, String, Color, MyOwnClass).

我该怎么做?

推荐答案

要沿这条路线走,您需要为每个属性创建一个自定义的 PropertyDescriptor .然后,您可以通过自定义 TypeConverter 或(或者) ICustomTypeDescriptor / TypeDescriptionProvider 公开它.示例:

To go down this route, you would need to create a custom PropertyDescriptor per property. You would then expose that via a custom TypeConverter, or (alternatively) ICustomTypeDescriptor/TypeDescriptionProvider. Example:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
[TypeConverter(typeof(CustomObjectType.CustomObjectConverter))]
public class CustomObjectType
{
    [Category("Standard")]
    public string Name { get; set; }
    private readonly List<CustomProperty> props = new List<CustomProperty>();
    [Browsable(false)]
    public List<CustomProperty> Properties { get { return props; } }

    private Dictionary<string, object> values = new Dictionary<string, object>();

    public object this[string name]
    {
        get { object val; values.TryGetValue(name, out val); return val; }
        set { values.Remove(name); }
    }

    private class CustomObjectConverter : ExpandableObjectConverter
    {
        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            var stdProps = base.GetProperties(context, value, attributes);
            CustomObjectType obj = value as CustomObjectType;
            List<CustomProperty> customProps = obj == null ? null : obj.Properties;
            PropertyDescriptor[] props = new PropertyDescriptor[stdProps.Count + (customProps == null ? 0 : customProps.Count)];
            stdProps.CopyTo(props, 0);
            if (customProps != null)
            {
                int index = stdProps.Count;
                foreach (CustomProperty prop in customProps)
                {
                    props[index++] = new CustomPropertyDescriptor(prop);
                }
            }
            return new PropertyDescriptorCollection(props);
        }
    }
    private class CustomPropertyDescriptor : PropertyDescriptor
    {
        private readonly CustomProperty prop;
        public CustomPropertyDescriptor(CustomProperty prop) : base(prop.Name, null)
        {
            this.prop = prop;
        }
        public override string Category { get { return "Dynamic"; } }
        public override string Description { get { return prop.Desc; } }
        public override string Name { get { return prop.Name; } }
        public override bool ShouldSerializeValue(object component) { return ((CustomObjectType)component)[prop.Name] != null; }
        public override void ResetValue(object component) { ((CustomObjectType)component)[prop.Name] = null; }
        public override bool IsReadOnly { get { return false; } }
        public override Type PropertyType { get { return prop.Type; } }
        public override bool CanResetValue(object component) { return true; }
        public override Type ComponentType { get { return typeof(CustomObjectType); } }
        public override void SetValue(object component, object value) { ((CustomObjectType)component)[prop.Name] = value; }
        public override object GetValue(object component) { return ((CustomObjectType)component)[prop.Name] ?? prop.DefaultValue; }
    }
}


public class CustomProperty
{
    public string Name { get; set; }
    public string Desc { get; set; }
    public object DefaultValue { get; set; }
    Type type;

    public Type Type
    {
        get
        {
            return type;
        }
        set
        {
                type = value;
                DefaultValue = Activator.CreateInstance(value);
        }              
    }
}

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        var obj = new CustomObjectType
        {
            Name = "Foo",
            Properties =
            {
                new CustomProperty { Name = "Bar", Type = typeof(int), Desc = "I'm a bar"},
                new CustomProperty { Name = "When", Type = typeof(DateTime), Desc = "When it happened"},
            }
        };
        Application.Run(new Form { Controls = { new PropertyGrid { SelectedObject = obj, Dock = DockStyle.Fill } } });
    }
}

这篇关于如何在属性网格中显示动态对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆