一,需求
在Winform中,默认情况下,按下Tab键,光标会按照我们设定的TabIndex值从小到大进行跳转。
但如果用户要求按下Tab键跳转到特定的控件,这种要求还是很合理的,比如用户只想输入几个必须填的项目。
我们可以在配置文件中配置这些必须填写的项目,并设定他们的跳转顺序。这样程序也更加灵活,利于扩展。
二,探索实现方法
1,在每个输入控件的keyDown事件里判断是Tab键,做相应的跳转处理。
最后调查发现按下Tab键,并不会触发控件keyDown事件,Tab键默认被系统处理了,悲剧了。
另外,输入项目太多的时候,这个做法工作量也太大了,不可行。
2,找一个全局点控制,而不分散到每个控件来处理。
方法就是利用Form本身的ProcessCmdKey方法。
看代码吧,备注已经写的很明白了
Dictionary<string, string> tabMap = new Dictionary<string, string>(); private void InitTabMap() { // 加入From,To的控件名称,表示按下Tab键从From跳掉To位置 tabMap.Add("textBox3", "textBox7"); tabMap.Add("textBox7", "textBox8"); } /// <summary> /// 这个重载函数里可以预先捕捉到一些按键,比如被系统默认捕获了的Tab键 /// 如果要改写Tab键的默认动作,要返回true,表示你已经处理过这个按键了 /// </summary> /// <param name="msg"></param> /// <param name="keyData"></param> /// <returns></returns> protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { Control ctl = this.ActiveControl; if (keyData == Keys.Tab) { if (ctl != null && tabMap.Keys.Contains(ctl.Name)) { var toCtrls = this.Controls.Find(tabMap[ctl.Name], true); if (toCtrls.Length > 0) { //检查父容器是否是隐藏的 ActivieParentContainerIfNeeded(toCtrls[0]); toCtrls[0].Focus(); //确实获得了焦点,再吞噬这个按键动作 if (toCtrls[0].Focused) { return true; } } } } bool ret = base.ProcessCmdKey(ref msg, keyData); return ret; } /// <summary> /// 有一些控件隐藏在了TabControl的后面,造成Focus不成功。 /// 因为这些控件的Visible为False,必须先使他们的父控件TabPage先选中 /// </summary> /// <param name="child"></param> private void ActivieParentContainerIfNeeded(Control child) { if (child.Visible) { return; } Control parent = child.Parent; while (parent != null) { if (parent is TabPage) { break; } parent = parent.Parent; } if (parent is TabPage) { TabControl tabCtrl = (TabControl)parent.Parent; tabCtrl.SelectedTab = (parent as TabPage); } }
上面的tabMap,在实际应用中应该从配置文件中读取。