[RequiredFieldAttribute]
public System.Windows.Forms.TextBox textBox1;
只需要在控件上加上[RequiredFieldAttribute],我们就可以让检验变得自动化。
首先我们需要一个验证用的属性Attribute,关于该属性的介绍可以参看MSDN。
public class RequiredFieldAttribute:Attribute,IDisposable
{
public RequiredFieldAttribute()
{
Validating_EventHandler = new CancelEventHandler(Validate);
}
private void Validate(object sender, CancelEventArgs e)
{
Control ctr = sender as Control;
e.Cancel = (ctr.Text == "");
}
public CancelEventHandler ValidatingDelegate
{
set{
Validating_EventHandler = value;
}
get
{
return Validating_EventHandler;
}
}
CancelEventHandler Validating_EventHandler;
#region IDisposable 成员
public void Dispose()
{
Validating_EventHandler = null;
}
#endregion
}
在定义好属性之后,就可以像前面说的那样将属性附加到我们要验证的控件上去:
[RequiredFieldAttribute]
public System.Windows.Forms.TextBox textBox1;
不过这里要求该控件的定义是“public”的,后面会讲到为什么。附加的属性不会自己起作用,除非是.net framework中默认那些,对于我们自己定义的属性CLR并不了解,所以要使自己定义的属性起作用,还需要自己做一些工作。下面我们定义一个ValidatorEngine的类:
public class ValidatorEngine
{
public ValidatorEngine(ContainerControl container)
{
this.container = (ContainerControl)container;
this.typeOfContainer = container.GetType();
}
public void Active()
{
Active(this.container);
}
private void Active(ContainerControl container)
{
//get all public fields
FieldInfo[] fields = typeOfContainer.GetFields();//1
foreach (FieldInfo fi in fields)
{
//get attributes assigned to the field
object[] attributes = fi.GetCustomAttributes(false);//2
foreach (Attribute attr in attributes)
{
RequiredFieldAttribute validator = attr as RequiredFieldAttribute;//3
if (validator != null)
{
Control[] childControls = container.Controls.Find(fi.Name, false);//4
//the number of child controls should always be "1"
if(childControls.Length>0)
//register validator defined in RequiredFieldAttribute for our controls
childControls[0].Validating += validator.ValidatingDelegate;//5
}
}
}
}
Type typeOfContainer;
ContainerControl container;
}
engine做了些什么工作?
- 取得容器控件(比如我们的Form)的所有公开(public)的字段。设为public的可以取到,设计器默认的private好像取不到,试验了加上BindingFlags的枚举好像也不行,如果有知道的请留言告知:)
- 对于一个字段,读取附加到它上面的自定义属性。参数是表示是否要搜说该字段所继承的属性,这里不需要所以设为false。
- 判断找到的属性是不是我们所设定的,即RequiredFieldAttribute,如果是那说明这个字段表示的控件是不许为空的。
- 如果控件前面有我们附加的属性,那么通过字段名找到这个控件。本例子中的控件就在容器控件的第一级子控件集合中,所以Find的第2个参数为false,不在更深的层次中搜索。
- 给控件注册Validating事件。例子中使用了我们在RequiredFieldAttribute类中设定的处理方法,这样可以让各种类似的控件使用相同的验证代码。如果要自定验证方法,可以通过:
public CancelEventHandler ValidatingDelegate 属性传入,但是这样我们附加属性的代码就与前面的略微有一些不同了,需要使用到属性的命名参数,请参考MSDN:
[RequiredFieldAttribute(ValidatingDelegate =yourValidatingHandler)]
public System.Windows.Forms.TextBox textBox1;
private void FormBase_Load(object sender, EventArgs e)
{
//give engine the reference of a ContainerControl
engine = new ValidatorEngine(this);
//start then engine ,it will process our custom attributes
engine.Active();
}
//define a engine
ValidatorEngine engine;
这个例子很简单,只有一个自定义属性,但是它已经可以让我们看到Attribute的威力了。
没有评论:
发表评论