在运行时生成的属性(PropertyGrid.SelectedObject) [英] Properties generated at runtime (PropertyGrid.SelectedObject)

查看:726
本文介绍了在运行时生成的属性(PropertyGrid.SelectedObject)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,这是一个艰难的一个

Ok, this is a tough one.

简介:我的想法是连接我写了一个实例化的QueryBuilder类,一PropertyGrid中。该QueryBuilder的类现在包含几个字段,这是硬编码就像在下面的例子中。从而允许用户指定,这字段应该在什么样的方式(排序,分组等)的查询中使用。具有特定后的用户的所有这些属性的设置(通过代码或通过PropertyGrid中的GUI),所述的QueryBuilder能够产生一个查询。一切工作正常这样。伪代码:

Introduction: My idea is to attach an instanciated QueryBuilder class which I wrote, to a PropertyGrid. The QueryBuilder class now contains a couple of fields, which are hardcoded like in the example below. Thus allowing a user to specify, which fields should be used in a query in what way (sorted, grouped, and so on). After the user having specified all the settings to these properties (by code or via the PropertyGrid GUI), the QueryBuilder is able to produce a query. Everything is working fine like that. Pseudo code:

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;}
}



挑战立即代替硬编码每个字段作为QueryBuilder的类公共属性,我不知道我怎么会用即列表<串> 包含我的所有领域,以填充我的实例化QueryBuilder的这些特性

Challenge: Now instead of hardcoding each field as public properties in the QueryBuilder class, I was wondering how I could use i.e. a List<string> containing all my fields to "populate" my instanciated QueryBuilder with these properties.

因此,这将导致三个问题:

So this leads to three questions:


  1. 莫非这由QueryBuilder的类的类型莫名其妙压倒一切的GetProperties()来完成,如果是,它怎么做最好?

  1. Could this be accomplished by somehow overriding GetProperties() of the Type of the QueryBuilder class, and if yes, how is it best done?

我如何再通过所有这些循环在运行时产生的QBField性能和实例化呢?理念:的PropertyDescriptor和活化

How can I then iterate through all of these at runtime generated QBField properties and instanciate them? Idea: PropertyDescriptors and Activators?

我如何能够通过所有这些属性的循环读取每个值QBField对象?我跑的问题是,随着反射阅读QBField的属性时,努力的getValue(OBJ,空),当然所需要的第一个参数是一个对象,我不知道,因为我有很多这些QBField对象。也许,把我所有的QBFields成列表与LT; QBField> ,并通过它迭代?将在此示例中的工作?

How can I iterate through all of these properties to read the values of each QBField object? The problem I ran in was, that when reading the Properties of QBField with reflection and trying getValue(obj, null), of course the first parameter needed is an object, which I do not know since I have lots of these QBField objects. Perhaps putting all my QBFields into a List<QBField> and iterating through it? Would that work in this example?

我只是有点失落,但我觉得我是非常接近的解决方案。因此,任何帮助或在正确的方向只是指针最不胜感激!

I'm just a bit lost but I feel that I'm very close to the solution. Therefore any help or just pointers in the right direction are most greatly appreciated!

推荐答案

的PropertyGrid 可以通过的TypeConverter ICustomTypeDescriptor 和/或 TypeDescriptionProvider 。其中,的TypeConverter 是最简单的,通过重写的GetProperties (并将其标记为支持)。

PropertyGrid can be influenced via TypeConverter, ICustomTypeDescriptor and/or TypeDescriptionProvider. Of these, TypeConverter is the simplest, by overriding GetProperties (and mark it as supported).

在任何情况下,你也需要编写一个知道如何采取领域和对象,并获得了的PropertyDescriptor 执行/设置的值,即

In any event, you will also need to write a PropertyDescriptor implementation that knows how to take a field and an object, and get/set the value, i.e.

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






下面是一个的基本的暴露一切为字符串属性包;显然当你扩展这个(不同的物业类型,更改通知等),它变得更加复杂非常快。还需要注意的是这个的TypeConverter 办法仅适用于的PropertyGrid ;为 DataGridView的等您将需要 ICustomTypeDescriptor TypeDescriptionProvider 。对于集合,你需要 ITypedList 。并有各地的具体情况下的边缘大约20等接口。但你明白了吧; P中的关键的一点是,我们的的PropertyDescriptor 作为(在我的案件的字典)您的实际的模式之间的转换,和模型,你暴露在 TypeDescriptor (假性质每个键)。


Here's a basic property bag that exposes everything as string; obviously as you extend this (different property types, change-notification, etc) it gets more complex very quickly. Note also that this TypeConverter approach only works for PropertyGrid; for DataGridView etc you'll need either ICustomTypeDescriptor or TypeDescriptionProvider. For collections you'll need ITypedList. And there are about 20 other interfaces around the edges for specific scenarios. But you get the point ;p The key thing is that our PropertyDescriptor acts as the translation between your actual model (the dictionary in my case), and the model you expose to TypeDescriptor (the fake properties per key).

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); } }
    }

}

这篇关于在运行时生成的属性(PropertyGrid.SelectedObject)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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