C# 自定义Attribute 允许参数字符代码 类似执行字符串代码

本文介绍了如何利用Attribute和反射在PropertyGrid控件中实现动态下拉列表源。通过自定义DisplayListSourceAttribute和DropDownListConverter,实现了根据字段、属性或方法动态获取下拉选项,支持常量和变量。示例代码展示了如何在Person类的PsName属性中应用此技术,动态获取PubV类的PersonNames字段作为下拉列表选项。
摘要由CSDN通过智能技术生成

  • Attribute特征参数只允许常量或类型(Type)

本文不论性能及合理性,只叙述实现动态传参 

[Category("基本属性")]
[Browsable(true), ReadOnly(true)]
[DisplayName("ID"), Description("控件ID")]
public string ID{ get; set; }

[Category("文字属性")]
[Browsable(true), ReadOnly(false)]
[DisplayName("文本内容")]
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
public string Text { get; set; }
  • 废话不多说,就以 PropertyGrid控件举例具体说说如何动态给Attribute传参

如果某一个属性是下拉列表选择的,但下拉列表项又是变化的,下图是固定不变的(废图)

当然直接读库或配置也可以,但需要代码自定义很多Attribute来供其它代码来调用获取验证

......
PsNameAttribute特征
//人员姓名 PropertyGrid控件姓名选择下拉 
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
 {    //调用静态类中输入项字段,写死的
     return new StandardValuesCollection(PubV.InputPS.Keys.ToArray());
 }

PsSexAttribute特征
//人员性别 PropertyGrid控件性别选择下拉
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
 {    //写死的
     return new StandardValuesCollection(new string[]{"男","女"});
 }

.......

  • 那我们如何使下拉框中的值是变化呢?

        说到"动态"/"字符串代码"一搜一大把,都是使用编译器...可是使用编译器太沉重了,我只是获取一组数据甚至一个值,当然我的方法还是用反射,就用 InvokeMember 动态调用,它有好多重载具体请查阅MSDN 官方文档,我们只使用最基本的方法:

public object InvokeMember(string name, BindingFlags invokeAttr, 
Binder binder, object target, object[] args)
// InvokeMember说明:
//调用成员所在类型.InvokeMember("调用成员",成员修饰,不理解null就行,如果是实例成员此处为实例,参数)
 object result = mType.InvokeMember("Name",
                     BindingFlags.Public |
                     BindingFlags.Static |
                     BindingFlags.GetField, null, null, null);
  • 示例:在PropertyGrid控件中下拉列表中选择人员姓名,人员列表可变

1.自定义Attribute特征 作为下拉列表源 同时支持常量及变量(字段/属性/方法)

//1.自定义Attribute特征 作为下拉列表源 同时支持常量及变量(字段/属性/方法)
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class DisplayListSourceAttribute : Attribute
    {
        public Type SourceType { get; set; }//成员所在类型(可以认为是类)
        public string InvokeName { get; set; }//调用成员名称(可以认为是字段/属性/方法名)
        public System.Reflection.BindingFlags BindFlags { get; set; }//成员修饰
        public object[] Param { get; set; }//参数,如果调用有参方法需要
        public string[] list { get; set; }//常量传参时用

        public DisplayListSourceAttribute(string[] values)//常量值构造
        {
            list = values;
        }

        public DisplayListSourceAttribute(Type t, string name, 
            System.Reflection.BindingFlags flag, params object[] pm)//变量值构造
        {
            SourceType = t;
            InvokeName = name;
            BindFlags = flag;
            Param = pm;
        }
    }

 2.自定义下拉列表转换器

//2.自定义下拉列表转换器
public class DropDownListConverter : StringConverter
{
   public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
   {
       return true;
   }
   public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
   {
       return false;
   }
   public override StandardValuesCollection GetStandardValues(
ITypeDescriptorContextcontext)
   {
        //获取下拉源特征
        DisplayListSourceAttribute attr =
                (DisplayListSourceAttribute)context.PropertyDescriptor
                .Attributes[typeof(DisplayListSourceAttribute)];
        //判断源是否为常量
        if (attr.list != null && attr.list.Length > 0)
            return new StandardValuesCollection(attr.list);
        else
        {
            if (attr.SourceType != null && !string.IsNullOrEmpty(attr.InvokeName))
            {
               //调用成员所在类型.InvokeMember("调用成员",
                          //成员修饰,不理解null就行,如果是实例此处为实例,参数)
               object list = attr.SourceType.InvokeMember(attr.InvokeName,
                          attr.BindFlags, null, null, attr.Param);
                if(list is ICollection)
                    return new StandardValuesCollection(list as ICollection);
                
            }
        }

        return null;
    }
}

 3.使用 在赋值给PropertyGrid的类中

//3.使用 在赋值给PropertyGrid的类中
[Category("人员信息")]
[Browsable(true), ReadOnly(false)]
[DisplayName("人员"), Description("请选择当前人员姓名")]
//下拉转换器DropDownListConverter
[TypeConverter(typeof(DropDownListConverter))]
//下拉源DisplayListSource,获取PubV静态类中的List<string>类型 PersonNames 字段
[DisplayListSource(typeof(PubV), "PersonNames",
            System.Reflection.BindingFlags.Public |
            System.Reflection.BindingFlags.Static |
            System.Reflection.BindingFlags.GetField, null)]
        public string PsName{ get; set; } = "";

Demo截图

         

  • 收工
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值