如何實現(xiàn)C# TextBox數(shù)字的輸入
C#旨在設(shè)計成為一種「簡單、現(xiàn)代、通用」,以及面向?qū)ο蟮某绦蛟O(shè)計語言。其中c# textbox數(shù)字輸入需要注意的一些情況容易被忽略,針對這一情況,筆者將在這篇文章中分享自己的一些經(jīng)驗。
最近看到一些關(guān)于c# textbox數(shù)字中限制只允許輸入數(shù)字的博文,這類問題常常用事后處理模式:錄入字符結(jié)束后在控件離開(如Exit事件)或確認時進行判斷。本文探討控件錄入操作的事前處理模式:做錄入操作時屏蔽非數(shù)字字符。下面,結(jié)合筆者前段時間修改完善的開源數(shù)值文框TNumEditBox控件,介紹一個基于定制c# textbox數(shù)字控件的解決方法。
在定制的c# textbox數(shù)字控件中,如果只允許輸入數(shù)字,需要考慮如下三種情況:
正常按鍵輸入的字符,包括西文、中文字符等
通過鍵盤快捷鍵方式貼入的文本,即Ctrl+V操作
通過上下文關(guān)聯(lián)菜單的Mouse操作貼入的文本,即”粘貼“操作
在探討的同類文章中,多數(shù)只考慮了第1種情況,忽略得了第2、3種常見的操作。本文探討的處理方法核心思路是重寫事件OnKeyPress()和兩個方法 ProcessCmdKey()與WndProc(),并把Ctrl+V、關(guān)聯(lián)菜單的Paste操作統(tǒng)一到鍵盤錄入操作中,從而在 OnKeyPress()屏蔽掉非數(shù)字鍵。
1、重寫鍵盤事件OnKeyPress()
鍵盤輸入的字符可以通過重寫c# textbox數(shù)字控件的OnKeyPress()事件處理,見如下代碼:
- protected override void OnKeyPress(KeyPressEventArgs e) // 屏蔽非數(shù)字鍵
- {
- base.OnKeyPress(e);
2、重寫命令鍵處理方法ProcessCmdKey()
可以在ProcessCmdKey()中捕獲快捷鍵Ctrl+V操作。首先要清除當(dāng)前的選擇文本,然后讀取剪切板ClipBoard中的內(nèi)容,最后通過模擬鍵盤輸入的方式”輸入“ClipBoard的內(nèi)容。需要指出,在ProcessCmdKey()方法中不能使用靜態(tài)方法 SendKeys.Send(),但可以通過控件的WndProc()方法發(fā)送字符消息以達到模擬鍵盤錄入的目的。見如下代碼:
- protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
- {
- if (keyData == (Keys)Shortcut.CtrlV) // 快捷鍵 Ctrl+V 粘貼操作
- private void SendCharKey(char c) // 通過消息模擬鍵盤錄入
- {
- Message msg = new Message();
3、重寫消息處理方法WndProc()
可以在定制c# textbox數(shù)字控件中創(chuàng)建無內(nèi)容的上下文菜單對象,從而屏蔽該菜單,方法是在定制控件的構(gòu)造函數(shù)中增加如下代碼:
- public class CustomTextBox: TextBox
- {
- // 創(chuàng)建無內(nèi)容菜單對象, 等價屏蔽該控件的上下文菜單
由于上下文菜單的Paste操作對應(yīng)Windows的WM_PASTE消息,于是可以在控件的WndProc()方法中捕獲該消息,然后獲得剪切板 ClipBoard中的內(nèi)容,最后通過SendKeys.Send()方法模擬鍵盤錄入操作。需要注意,這里不能調(diào)用前面ProcessCmdKey() 中模擬鍵盤輸入函數(shù)SendCharKey()。見如下代碼:
- protected override void WndProc(ref Message m) // 捕獲Mouse的Paste消息
- {
- if (m.Msg == WM_PASTE) // 選擇上下文菜單的"粘貼"操作 {
- this.ClearSelection();
- SendKeys.Send(Clipboard.GetText()); // 模擬鍵盤輸入
- }
- else
- {
- base.WndProc(ref m);
- }
- }
4、消除選擇ClearSelection()、刪除字符DeleteText()
還必須分析前面代碼中的兩個函數(shù):
ClearSelection()用以清除當(dāng)前的選擇文本,即清除this.SelectedText
DeleteText()則刪除當(dāng)前字符
需要指出其中的技巧,就是轉(zhuǎn)換Delete鍵操作為BackSpace操作。此外,函數(shù)DeleteText()還需要確定當(dāng)前的this.SelectionStart值。具體代碼如下:
- private void ClearSelection() // 清除當(dāng)前TextBox的選擇
- {
- if (this.SelectionLength == 0)
- {
- return;
- }
- int selLength = this.SelectedText.Length; this.SelectionStart += this.SelectedText.Length; // 光標在選擇之后
- this.SelectionLength = 0;
- for (int k = 1; k <= selLength; k++)
- {
- this.DeleteText(Keys.Back);
- }
- }
- private void DeleteText(Keys key) // 刪除字符并計算SelectionStart值
- {
- int selStart = this.SelectionStart;
- if (key == Keys.Delete) // 轉(zhuǎn)換Delete操作為BackSpace操作
- {
- selStart += 1;
- if (selStart > base.Text.Length)
- {
- return;
- }
- }
- if (selStart == 0 || selStart >base.Text.Length) // 不需要刪除
- {
- return;
- }
- if (selStart == 1 && base.Text.Length == 1)
- {
- base.Text = "";
- base.SelectionStart = 0;
- }
- else // selStart > 0
- {
- base.Text = base.Text.Substring(0, selStart - 1) +
- base.Text.Substring(selStart, base.Text.Length - selStart);
- base.SelectionStart = selStart - 1;
- }
- }
5、結(jié)語
本文探討的是c# textbox數(shù)字控件輸入的事前處理模式,即在輸入字符的同時屏蔽非數(shù)字鍵。在實際應(yīng)用中一般采取事后處理模式,即在c# textbox數(shù)字控件的Exit、Validate等事件中進行輸入后處理——離開該控時進行驗證。但事后處理模式有如下不足:
與數(shù)據(jù)源綁定時輸入非數(shù)字字符可能拋出異常,需要考慮異常捕獲
需要判斷數(shù)據(jù)并給出錯誤提示等處理
上述內(nèi)容是從筆者的開源數(shù)值型數(shù)據(jù)編輯控件TNumEditBox中修改刪減而來的,該控件考慮的情況比只允許數(shù)字輸入要復(fù)雜得多,感興趣者可以參考并指正。需要指出,TNumEditBox的核心思路來自免費的Delphi控件PBNumEdit和開源的C#控件BANumEdit。作為回報,筆者也將TNumEditBox開源并發(fā)布到CodeProject。
本文來自:CSDN博客 作者:huihui
【編輯推薦】