如何在运行时属性级别的属性添加到TypeDescriptor?(How to add propert

2019-06-17 21:22发布

我想一些自定义的PropertyGrid为中心的属性添加到该对象的属性,为客户提供更丰富的编辑,隐藏类别的一些价值观和他们组,因为该类我的工作并没有提供这样的功能,我不能做任何事情关于它。

真的,它是生成代码MS的应用程序设置,这样你就可以以任何方式财产明智不会延长。 见我的其他问题: 运行AppSettings.settings编辑器对话框

Answer 1:

不像其他人所说,这是完全可能的,也并不难。 例如,你想一些新的属性添加到一些属性,你可以根据某些条件在运行时进行选择。

还有就是我们需要实现这两个辅助类。

首先去PropertyOverridingTypeDescriptor ,它使我们能够提供我们自己的财产描述符的某些属性,而保持其他不变:

public class PropertyOverridingTypeDescriptor : CustomTypeDescriptor
    {
        private readonly Dictionary<string, PropertyDescriptor> overridePds = new Dictionary<string, PropertyDescriptor>();

        public PropertyOverridingTypeDescriptor(ICustomTypeDescriptor parent)
            : base(parent)
        { }

        public void OverrideProperty(PropertyDescriptor pd)
        {
            overridePds[pd.Name] = pd;
        }

        public override object GetPropertyOwner(PropertyDescriptor pd)
        {
            object o = base.GetPropertyOwner(pd);

            if (o == null)
            {
                return this;
            }

            return o;
        }

        public PropertyDescriptorCollection GetPropertiesImpl(PropertyDescriptorCollection pdc)
        {
            List<PropertyDescriptor> pdl = new List<PropertyDescriptor>(pdc.Count+1);

            foreach (PropertyDescriptor pd in pdc)
            {
                if (overridePds.ContainsKey(pd.Name))
                {
                    pdl.Add(overridePds[pd.Name]);
                }
                else
                {
                    pdl.Add(pd);
                }
            }

            PropertyDescriptorCollection ret = new PropertyDescriptorCollection(pdl.ToArray());

            return ret;
        }

        public override PropertyDescriptorCollection GetProperties()
        {
            return GetPropertiesImpl(base.GetProperties());
        }
        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return GetPropertiesImpl(base.GetProperties(attributes));
        }
    }

几句话:

  • 构造函数采用ICustomTypeDescriptor ,不用担心在这里,我们可以得到一个对任何类型或它的实例与TypeDescriptor.GetProvider(_settings).GetTypeDescriptor(_settings)其中_settings可以是Typeobject该类型的。
  • OverrideProperty不正是我们所需要的,更多的后来。

我们需要的其他类是TypeDescriptionProvider将返回我们的自定义类型说明符而不是默认的。 这里是:

public class TypeDescriptorOverridingProvider : TypeDescriptionProvider
    {
        private readonly ICustomTypeDescriptor ctd;

        public TypeDescriptorOverridingProvider(ICustomTypeDescriptor ctd)
        {
            this.ctd = ctd;
        }

        public override ICustomTypeDescriptor GetTypeDescriptor (Type objectType, object instance)
        {
            return ctd;
        }
    }

相当简单:您只需提供建筑类型描述实例,并在这里你去。

最后,处理代码。 例如,我们希望所有的属性与结尾ConnectionString在我们的对象(或类型) _settings可编辑与System.Web.UI.Design.ConnectionStringEditor 。 为了实现这一点,我们可以使用此代码:

// prepare our property overriding type descriptor
PropertyOverridingTypeDescriptor ctd = new PropertyOverridingTypeDescriptor(TypeDescriptor.GetProvider(_settings).GetTypeDescriptor(_settings));

// iterate through properies in the supplied object/type
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(_settings))
{
    // for every property that complies to our criteria
    if (pd.Name.EndsWith("ConnectionString"))
    {
        // we first construct the custom PropertyDescriptor with the TypeDescriptor's
        // built-in capabilities
        PropertyDescriptor pd2 =
            TypeDescriptor.CreateProperty(
                _settings.GetType(), // or just _settings, if it's already a type
                pd, // base property descriptor to which we want to add attributes
                    // The PropertyDescriptor which we'll get will just wrap that
                    // base one returning attributes we need.
                new EditorAttribute( // the attribute in question
                    typeof (System.Web.UI.Design.ConnectionStringEditor),
                    typeof (System.Drawing.Design.UITypeEditor)
                )
                // this method really can take as many attributes as you like,
                // not just one
            );

        // and then we tell our new PropertyOverridingTypeDescriptor to override that property
        ctd.OverrideProperty(pd2);
    }
}

// then we add new descriptor provider that will return our descriptor instead of default
TypeDescriptor.AddProvider(new TypeDescriptorOverridingProvider(ctd), _settings);

就是这样,现在结束所有属性ConnectionString会通过编辑ConnectionStringEditor

正如你所看到的,我们只是覆盖默认实现的一些功能每一次,所以系统应该是相当稳定的,像预期的那样。



Answer 2:

如果你需要添加像[ExpandableObject]或[编辑]对类,你不能修改您可以将属性添加到属性的类型对象的属性属性。 所以,你可以使用反射来检查对象,并使用

TypeDescriptor.AddAttributes(typeof (*YourType*), new ExpandableObjectAttribute());

然后,它像你装饰的属性类型YourType的所有属性。



Answer 3:

如果你想定制丰富的PropertyGrid,另一种设计是为了让你的包裹你的类型,一类从CustomTypeDescriptor继承。 然后,您可以覆盖的GetProperties,标注有需要的PropertyGrid属性的基础类的属性。

一个相关的问题回答中详细描述https://stackoverflow.com/a/12586865/284795



Answer 4:

接受答案的工作,但它也有缺陷:如果您指定的供应商基类,它也是会工作的派生类,但是,由于PropertyOverridingTypeDescriptor父(从中会得到它的属性)是基类型,派生类型只能找到的基类的属性。 这导致了Havok在例如,设计师的WinForms(并可能导致你,如果你使用的是数据丢失TypeDescriptor序列化的数据)。

只是为了记录在案,我做了基于@ GMAN的答案一个通用的解决方案,我已经张贴在这里作为解决自己的问题(这是一个不同的问题,但解决方案使用此一个能用的)。



文章来源: How to add property-level Attribute to the TypeDescriptor at runtime?