一,需求
在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,在實際應用中應該從配置文件中讀取。

