如何在运行时向 TypeDescriptor 添加属性级 Attribute?

2024-05-24

我想向对象的属性添加一些自定义的以 PropertyGrid 为中心的属性,以提供更丰富的编辑、隐藏一些值并将它们分组到类别中,因为我正在使用的那个类不提供此类功能,我无能为力关于它。

实际上,它是为 MS 的应用程序设置生成代码的,因此您无法以任何方式在属性方面扩展它。请参阅我的另一个问题:Runtime AppSettings.settings 编辑器对话框 https://stackoverflow.com/questions/12042056/runtime-appsettings-settings-editor-dialog/12042754


与其他人建议的不同,这是很有可能的,而且也不那么难。例如,您想添加some新属性some属性,您可以在运行时根据某些条件选择这些属性。

我们需要两个辅助类来实现这个。

首先PropertyOverridingTypeDescriptor,它允许我们提供我们自己的属性描述符some属性,同时保持其他属性完好无损:

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 可以是Type or object那种类型的。
  • 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.

正如您所看到的,我们每次都只是重写默认实现的一些功能,因此系统应该相当稳定并按预期运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在运行时向 TypeDescriptor 添加属性级 Attribute? 的相关文章

随机推荐

  • Java监听按钮和键盘点击

    如何监听按下的按键并触发 JButton 例如 我在面板上有 A JButton 作为 GUI 我在 aButton 上实现了一个按钮监听器 它将把屏幕更改为其他内容 我希望通过鼠标单击和按下键盘来触发此按钮 如何通过按键盘上的 a 来触发
  • 为什么“0 && true”在 JavaScript 中返回 0 而不是布尔值?

    我确信 Javascript 中的任何逻辑表达式都会返回布尔值 但该表达式返回数字 0 而不是布尔值 0 true gt 0 为什么会这样 在这种情况下 我该如何处理 Javascript 中的逻辑表达式以防止将来出现此类错误 背景故事 我
  • 无法访问 Github 403 错误:权限被拒绝

    我是 Git Github 的新手 所以请原谅我的困惑 问题是 我刚刚对本地存储库进行了更改 并且想推送到 Github 上的原点 特别是 gh pages 之前 我一直在使用另一个 Github 帐户 因此我更改了 user name 和
  • 可从数组观察

    我目前对 Angular2 和 Observable 对象有疑问 我有一个调用服务的组件 一个链接到 api 的真实组件和一个假组件 链接到 API 的服务运行良好 但当我使用假的服务时 我想从 Observable 对象返回一个数组 但出
  • MSTest 与 Moq - DAL 设置

    我是最小起订量新手 刚刚开始一个已经在开发的项目 我负责设置单元测试 DatabaseFactory 有一个使用 EnterpriseLibrary 的自定义类 如下所示 public Database CreateCommonDataba
  • 使用 PDFSharp 打印 PDF

    我有以下代码 using System using System Diagnostics using System IO using PdfSharp Pdf Printing namespace PrintPdfFile class Pr
  • jQuery DataTables 获取选定行的值

    我正在使用 jQuery 数据表 我使用http www datatables net examples api select row html http www datatables net examples api select row
  • PayPal 沙箱 API 凭证丢失?

    我正在使用 PayPal 经典 API 当我尝试获取沙箱测试帐户 API 凭据时 我看到下面的空白屏幕 谁能告诉我发生了什么事吗 最后我成功了 这有效 注销 Paypal 帐户 清除浏览器缓存和cookie 我使用firefox 访问dev
  • 具有多个验证组的 Page_ClientValidate() - 如何同时显示多个摘要?

    ASP NET 2 0 假设我有两个验证组 valGrpOne 和 valGrpTwo 以及两个验证摘要 valSummOne 和 valSummTwo 分解部分的原因纯粹是为了美观 一个提交按钮会触发对两组的验证 现在我想触发客户端验证
  • Outlook 2007 捕获 ReplyToAll 事件的共享加载项

    我正在使用 VS 2010 和 Dot Net Framework 2 0 我已在 扩展性 gt Outlook 共享加载项 中创建了一个项目 我正在尝试捕获 ReplyToAll 事件 但它没有被解雇 请看下面的代码 连接方法 inspe
  • Postgres LEFT JOIN 与 WHERE 条件

    我需要使用 where 条件左连接两个表 Table time table id rid start date end date 1 2 2017 07 01 00 00 00 2018 11 01 00 00 00 2 5 2017 01
  • 简单的openGL程序无法在ubuntu中链接

    我正在尝试进入 opengl 编程 但无法编译我的第一个非常非常简单的程序 链接过程每次都会失败 我发现这个答案 https stackoverflow com questions 859501 learning opengl in ubu
  • 尝试使用 ui-router 让一个子视图调用另一个子视图

    我有两个子视图 一个用于类别 一个用于产品 因此是该类别的产品 我希望用户能够选择一个类别并查看该类别的所有产品 所以我在类别控制器中调用一个函数View单击类别行上的按钮 这是函数 self scope viewSalonProducts
  • 为什么重写本机方法是一个坏主意?

    我发布了一个我压倒一切的问题push using Object defineProperty 原来的问题是here https stackoverflow com questions 38096124 calling original me
  • 两个滚动视图同时工作,一键触摸

    我正在其中开发应用程序 我必须一键同时处理两个滚动视图 这意味着如果我同时滚动一个滚动视图 另一个滚动视图必须随之滚动 如果这是可能的 那么如何才能做到呢 在包含两个滚动视图的视图控制器中实现 UIScrollViewDelegate 协议
  • nginx + php-fpm = 找不到文件

    当我尝试访问时info php我得到一个File not found error 我尝试了一些教程但无济于事 配置 默认 server listen 80 listen 80 default ipv6only on server name
  • 从 Azure 密钥保管库存储和检索 JKS

    我想引用 Azure Key Vault 中的 Java 密钥存储 而不是将其与作为 docker 映像部署到 Kubernetes 集群中的 Spring Boot 应用程序打包在一起 根据 Azure 文档 仅允许将 PFX 文件导入到
  • 停止引导程序轮播在幻灯片末尾循环

    我想要这样 当我按下轮播上的下一个按钮时 如果它已到达幻灯片的末尾 则不要绕回并返回到第一张幻灯片 Bootstrap 3 有没有简单的方法可以做到这一点 设置wrap选项为 false 会使轮播自动停止循环 myCarousel caro
  • 如何使用复选框来过滤 Angular 的结果?

    我正在尝试使用复选框应用过滤器 复选框正确显示 div div
  • 如何在运行时向 TypeDescriptor 添加属性级 Attribute?

    我想向对象的属性添加一些自定义的以 PropertyGrid 为中心的属性 以提供更丰富的编辑 隐藏一些值并将它们分组到类别中 因为我正在使用的那个类不提供此类功能 我无能为力关于它 实际上 它是为 MS 的应用程序设置生成代码的 因此您无