在Winform开发中对事件的使用比较多,这里使用Winform中的自定义控件开发来对事件的实际用途举一个例子,这个例子实现的效果在不使用事件时还是比较难实现的,正好也突出了事件的实际应用价值
需求分析:开发过条码枪设备的人应该知道,条码枪的窗体界面的一个最基本的需求就是在一行条码扫描完成后将焦点自动移动到下一个输入框中,由于输入的条码长度不一定相等,所以比较普遍的做法是捕获条码枪输入后自动加入的回车键(即 KeyValue==“Return”),这样说的话,能看出其实很类似与PC开发上的Tab,也就是Control基类对于Tab的处理。
设计:从上面的分析很容易得出结论:只需要在自定义控件中捕获Textbox的KeyDown事件进行判断,如果输入了“Return”,就讲Focus交给下一个注册的控件,和TabIndex一样,我将这个注册属性命名为EnterIndex,分析后的结构大概如下:
为了提高公用性,将对失去焦点的事件(EnterChange)激发放在Inbox中,将对EnterChange事件的定义放在UserControlBase基类中,这样,以后新增需要使用EnterChange事件的控件时只需要继承UserControlBase基类,然后激发该类的EnterChange事件就可以了
为了使用户对Form的开发更为简洁,将对用户点击enter事件后的处理放在BaseForm中,由BaseForm遍历Form2中的控件,找出其中具有EnterIndex属性的控件,并记录下来,这样,以后新增需要使用点击回车就将焦点跳到下一个控件这样的操作时,只需要继承BaseForm就行了。
这样设计就面临一个问题,即:捕获用户点击Enter的类是UserControlBase,而具有实际处理能力的类是BaseForm,两者之间没有继承,实现,等任何关系,为了实现解耦,更不能将BaseForm直接传给UserControlBase。
现在就能体现出事件的用处了,在BaseForm对Form2的控件遍历中,可以为所有具有Enterindex属性的控件注册EnterChange事件的处理方法,这样,在UserControlBase上的EnterChange事件被激发后就能调用BaseForm中的实际处理方法,从而实现上述功能。
注:在遍历Form2找出控件是否具有EnterIndex属性时,我使用as进行判断该控件是否继承自基类UserControlBase,如果大家感觉这样实现还是有耦合性的话,也可以使用反射来判断其是否具有该属性,但是由于本例的用户控件使用在Wince上,需要对性能进行优化,而反射是公认的性能杀手,所以我不再使用。
实现:代码如下:
public partial class BaseForm : Form { public DictionaryControlTable = new Dictionary (); public BaseForm() { InitializeComponent(); } public void FocusNext(int argIndex) { if (ControlTable != null) { UserControlBase controlBase = null; int enterIndex = argIndex; if (ControlTable.TryGetValue(enterIndex + 1, out controlBase)) { if (controlBase != null) { controlBase.Focus(); } } } } public void SetControlList(BaseForm childForm) { foreach (Control control in childForm.Controls) { //获得继承自UserControlBase的控件 UserControlBase baseControl = control as UserControlBase; if (baseControl != null && baseControl.EnterIndex != -1 && ControlTable != null) { ControlTable.Add(baseControl.EnterIndex, baseControl); baseControl.EnterChange += this.EnterChange; } } } public void EnterChange(object sender, EnterChangeArgs args) { FocusNext(args.Index); } }
public partial class Form2 : BaseForm { public Form2() { InitializeComponent(); base.SetControlList(this); } }
public partial class UserControlBase : UserControl { public int EnterIndex { get; set; } public event EventHandlerEnterChange; public UserControlBase() { InitializeComponent(); } public void EnterValueChange(int index,string insertName,string insertValue) { //因为在实际使用的过程中还需要传递其他参数,所以我定义了 //EnterChangeArgs,如果不需要传递其他参数,直接使用EventArgs就行 EnterChangeArgs args = new EnterChangeArgs(); //省略无关代码 if (EnterChange != null) { EnterChange(this, args); } } }
public partial class InBox : UserControlBase { //省略无关代码 public InBox() { InitializeComponent(); } private void textBox1_KeyDown(object sender, KeyEventArgs e) { //省略无关代码 int index = this.EnterIndex; //省略无关代码 if (e.KeyData.ToString().Equals("Return")) { base.EnterValueChange(index, insertName,insertValue); } } }