如何在属性网格中显示动态对象? [英] How to display a dynamic object in property grid?
问题描述
我有一个自定义对象类型,必须在 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屋!