-
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截图
- 收工