Gre*_*vre 3 c# reflection propertygrid properties
好的,这是一个艰难的.
简介:我的想法是连接我写了一个实例化的QueryBuilder类,到PropertyGrid中.QueryBuilder类现在包含几个字段,这些字段是硬编码的,如下例所示.因此,允许用户指定,哪些字段应该以何种方式(排序,分组等)的查询使用.在用户为这些属性指定了所有设置后(通过代码或通过PropertyGrid GUI),QueryBuilder能够生成查询.一切都很好.伪代码:
class QueryBuilder {
public QBField name {get; set;}
public QBField prename {get; set;}
public QBField zip {get; set;}
// ...
public void QueryBuilder() {
name = new QBField();
prename = new QBField();
// ...
}
public getQuery() {
// logic to build the query
}
}
class QBField {
public bool shown {get; set;}
public bool sortby {get; set;}
public bool groupby {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
挑战:现在不是硬编码的每个字段作为QueryBuilder的类公共属性,我不知道我怎么会用即List<string>包含所有我的领域"填充"具有这些属性我实例化QueryBuilder的.
所以这导致了三个问题:
难道这由QueryBuilder的类的类型莫名其妙压倒一切的GetProperties()来完成,如果是,它是如何做得最好?
然后我如何在运行时生成QBField属性并在实例化时迭代所有这些?想法:PropertyDescriptors和Activators?
如何迭代所有这些属性来读取每个QBField对象的值?我遇到的问题是,当用反射读取QBField的属性并尝试getValue(obj,null)时,当然需要的第一个参数是一个对象,我不知道,因为我有很多这些QBField对象.也许把我所有的QBField都放进去List<QBField>并迭代它?这会在这个例子中起作用吗?
我只是有点迷失,但我觉得我非常接近解决方案.因此,非常感谢任何帮助或只是指向正确的方向!
PropertyGrid可通过影响TypeConverter,ICustomTypeDescriptor和/或TypeDescriptionProvider.其中,TypeConverter最简单的是,通过覆盖GetProperties(并将其标记为支持).
无论如何,您还需要编写一个PropertyDescriptor知道如何获取字段和对象的实现,并获取/设置值,即
public override void SetValue(object component, object value) {
((YourType)component)[fieldNameSetInConstructor] = value;
}
Run Code Online (Sandbox Code Playgroud)
这是一个基本的属性包,暴露一切为string; 显然,当您扩展它(不同的属性类型,更改通知等)时,它会变得更加复杂.另请注意,此TypeConverter方法仅适用于PropertyGrid; 为DataGridView等您将需要ICustomTypeDescriptor或TypeDescriptionProvider.对于您需要的收藏品ITypedList.对于特定场景,边缘周围还有大约20个其他接口.但是你得到了重点; p关键是我们的PropertyDescriptor行为是你的实际模型(在我的情况下是字典)和你暴露的模型TypeDescriptor(每个键的假属性)之间的转换.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var bag = new BasicPropertyBag { Properties = {
new MetaProp("Name", typeof(string)),
new MetaProp("Description", typeof(string)),
new MetaProp("DateOfBirth", typeof(DateTime)
, new CategoryAttribute("Personal"), new DisplayNameAttribute("Date Of Birth"))
} };
bag["Name"] = "foo";
bag["DateOfBirth"] = DateTime.Today;
Application.Run(new Form { Controls = { new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = bag } } });
}
}
public class MetaProp
{
public MetaProp(string name, Type type, params Attribute[] attributes)
{
this.Name = name;
this.Type = type;
if (attributes != null)
{
Attributes = new Attribute[attributes.Length];
attributes.CopyTo(Attributes, 0);
}
}
public string Name { get; private set; }
public Type Type { get; private set; }
public Attribute[] Attributes { get; private set; }
}
[TypeConverter(typeof(BasicPropertyBagConverter))]
class BasicPropertyBag
{
private readonly List<MetaProp> properties = new List<MetaProp>();
public List<MetaProp> Properties { get { return properties; } }
private readonly Dictionary<string, object> values = new Dictionary<string, object>();
public object this[string key]
{
get { object value; return values.TryGetValue(key, out value) ? value : null; }
set { if (value == null) values.Remove(key); else values[key] = value; }
}
class BasicPropertyBagConverter : ExpandableObjectConverter
{
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
PropertyDescriptor[] metaProps = (from prop in ((BasicPropertyBag)value).Properties
select new PropertyBagDescriptor(prop.Name, prop.Type, prop.Attributes)).ToArray();
return new PropertyDescriptorCollection(metaProps);
}
}
class PropertyBagDescriptor : PropertyDescriptor
{
private readonly Type type;
public PropertyBagDescriptor(string name, Type type, Attribute[] attributes)
: base(name, attributes) {
this.type = type;
}
public override Type PropertyType { get { return type; } }
public override object GetValue(object component) { return ((BasicPropertyBag)component)[Name]; }
public override void SetValue(object component, object value) { ((BasicPropertyBag)component)[Name] = (string)value; }
public override bool ShouldSerializeValue(object component) { return GetValue(component) != null; }
public override bool CanResetValue(object component) { return true; }
public override void ResetValue(object component) { SetValue(component, null); }
public override bool IsReadOnly { get { return false; } }
public override Type ComponentType { get { return typeof(BasicPropertyBag); } }
}
}
Run Code Online (Sandbox Code Playgroud)