WinForms 應用離不開鍵盤交互,但很多開發者僅停留在「能輸入」層面,忽略了事件順序、組合鍵判斷、輸入攔截與合規性校驗。本文系統梳理三大鍵盤事件機制,並給出生產級輸入驗證最佳實踐。
| 事件 | 觸發時機 | 核心參數/屬性 | 典型用途 |
|---|---|---|---|
| KeyDown | 按鍵按下瞬間 (最先) | KeyEventArgs.KeyCode, Modifiers (Shift/Ctrl/Alt), KeyData | 快捷鍵、導航、組合鍵檢測、取消輸入 |
| KeyPress | 產生字符時 (僅字符鍵) | KeyPressEventArgs.KeyChar (字符代碼) | 字符級過濾、大小寫判斷、攔截輸入 (Handled=true) |
| KeyUp | 按鍵釋放瞬間 (最後) | 同 KeyDown | 釋放觸發邏輯、配合 KeyDown 實現長按檢測 |
private void txt_KeyDown(object sender, KeyEventArgs e)
{
// 1. 組合鍵判斷
if (e.Control && e.KeyCode == Keys.S) // Ctrl+S
{
Save(); e.Handled = true; e.SuppressKeyPress = true; return;
}
// 2. 三鍵同時按下 (KeyData 包含 Keys + Modifiers)
if ((e.KeyData & (Keys.Control | Keys.Shift | Keys.Alt)) ==
(Keys.Control | Keys.Shift | Keys.Alt))
{
ShowTaskManager(); // 自定義邏輯
}
// 3. 導航鍵攔截 (防止焦點移動)
if (e.KeyCode == Keys.Tab) { e.Handled = true; /* 自定義 Tab 邏輯 */ }
}
private void txt_KeyPress(object sender, KeyPressEventArgs e)
{
// 僅允許數字、退格、小數點
if (!char.IsDigit(e.KeyChar) && e.KeyChar != '\b' && e.KeyChar != '.')
{
e.Handled = true; // 取消輸入
SystemSounds.Beep.Play(); // 聲音提示
}
// 單一小數點限制
if (e.KeyChar == '.' && ((TextBox)sender).Text.Contains("."))
e.Handled = true;
// 大小寫感知:KeyChar 已包含 Shift/CapsLock 狀態
// 'A' (65) vs 'a' (97) 直接判斷即可
}
private void txt_KeyUp(object sender, KeyEventArgs e)
{
// 長按檢測需配合 KeyDown 記錄時間戳
// 釋放時觸發「搜索建議」、「自動保存」等延遲邏輯
}
MaxLength 屬性 + KeyPress 中超長攔截彈窗/聲音。KeyPress 根據 SelectionStart 動態判斷允許字符集。ErrorProvider 顯示圖標 + ToolTip,避免彈窗打斷流程。TextChanged 或重寫 WndProc 攔截 WM_PASTE,統一走驗證邏輯。ReadOnly 仍觸發 KeyDown/KeyUp,Enabled=false 完全不觸發,按業務選擇。private void txtProductCode_KeyPress(object sender, KeyPressEventArgs e)
{
var tb = (TextBox)sender;
int pos = tb.SelectionStart;
if (e.KeyChar == '\b') return; // 允許退格
if (pos < 3) // 前三位:字母
{
if (!char.IsLetter(e.KeyChar)) { e.Handled = true; Beep(); }
else e.KeyChar = char.ToUpper(e.KeyChar); // 強制大寫
}
else if (pos == 3) // 第四位:自動插入連字符
{
if (e.KeyChar != '-') { tb.Text = tb.Text.Insert(3, "-"); tb.SelectionStart = 4; }
}
else // 後五位:數字
{
if (!char.IsDigit(e.KeyChar)) { e.Handled = true; Beep(); }
}
if (tb.Text.Length > 9) { e.Handled = true; Beep(); }
}
e.Handled = true 攔截輸入,e.SuppressKeyPress 抑制後續 KeyPress。ErrorProvider 即時反饋,拒絕「保存時才報錯」的糟糕體驗。