gpt4 book ai didi

c# - 运行时生成的属性 (PropertyGrid.SelectedObject)

转载 作者:行者123 更新时间:2023-11-30 15:09:44 25 4
gpt4 key购买 nike

好吧,这是一个艰难的过程。

简介:我的想法是将我编写的实例化 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;}
}

挑战:现在我想知道如何使用 List<string>,而不是将每个字段硬编码为 QueryBuilder 类中的公共(public)属性。包含我的所有字段以使用这些属性“填充”我的实例化 QueryBuilder。

因此这导致了三个问题:

  1. 是否可以通过某种方式覆盖 QueryBuilder 类的 Type 的 GetProperties() 来实现这一点?如果可以,如何最好地完成?

  2. 然后如何在运行时遍历所有这些生成的 QBField 属性并实例化它们?想法:PropertyDescriptors 和 Activators?

  3. 如何遍历所有这些属性以读取每个 QBField 对象的值?我遇到的问题是,当使用反射读取 QBField 的属性并尝试 getValue(obj, null) 时,当然需要的第一个参数是一个对象,我不知道,因为我有很多这些 QBField 对象。也许将我所有的 QBFields 放入 List<QBField>并遍历它?这在这个例子中行得通吗?

我只是有点迷茫,但我觉得我已经非常接近解决方案了。因此,非常感谢任何帮助或只是指向正确方向的指示!

最佳答案

PropertyGrid 可以通过 TypeConverterICustomTypeDescriptor 和/或 TypeDescriptionProvider 影响。其中,TypeConverter 是最简单的,通过覆盖 GetProperties(并将其标记为受支持)。

无论如何,您还需要编写一个 PropertyDescriptor 实现,它知道如何获取字段和对象,并获取/设置值,即

public override void SetValue(object component, object value) {
((YourType)component)[fieldNameSetInConstructor] = value;
}

这是一个基本属性包,它将所有内容公开为string;显然,当您扩展它(不同的属性类型、更改通知等)时,它会很快变得更加复杂。另请注意,此 TypeConverter 方法仅适用于 PropertyGrid;对于 DataGridView 等,您需要 ICustomTypeDescriptorTypeDescriptionProvider。对于集合,您需要 ITypedList。对于特定场景,边缘周围还有大约 20 个其他接口(interface)。但是你明白了 ;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); } }
}

}

关于c# - 运行时生成的属性 (PropertyGrid.SelectedObject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4091888/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com