關於WPF TextBox只能輸入數字並不是一個很難的功能,網上許多的實現方式都是通過將String類型轉換為Int32類型來進行判斷的,自從對了Clr Via C#這本書以后就對拆裝箱操作產生了恐懼,於是就想如果不(或者是減少)通過類型轉換的方式去實現會不會更好。
先做個測試,測試一下TextBox幾個關鍵關鍵事件的觸發順序:
PreviewKeyDown > KeyDown > PreviewTextInput > TextChanged > PreviewKeyUp > KeyUp
在上面的實踐中,在PreviewKeyDown和Keydown中都可以捕獲到按下的鍵值,在PreViewTextInput中可以獲取到當前輸入的字符,在TextChanged里面可以獲取到已經發生變化的TextBox的值和對應的Changed(e.Changes),接下來就是對應的KeyUp事件,在測試的時候還有一個TextInput的事件沒有觸發,不知道怎么回事,不過從字面上理解這個事件貌似也沒有什么用處,TextInput事件不知道處於一個什么樣的狀態。
通過上面的測試發現可以在PreviewKeyDown對用戶按下的鍵值進行判斷,代碼如下:
1 protected override void OnPreviewKeyDown(KeyEventArgs e) 2 { 3 if ((e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || 4 (e.Key >= Key.D0 && e.Key <= Key.D9) || 5 e.Key == Key.Back|| 6 e.Key==Key.Left||e.Key==Key.Right) 7 { 8 if (e.KeyboardDevice.Modifiers != ModifierKeys.None) 9 { 10 e.Handled = true; 11 } 12 } 13 else 14 { 15 e.Handled = true; 16 } 17 }
通過代碼可以看出在輸入時只允許按下的鍵值為數字和Backspace,並且不能是組合鍵。這樣就實現了不通過類型轉換實現了只能輸入數字的功能,在這里多說一點,一般這個功能還需要考慮到粘貼的問題,例如將一段內容從其他地方粘貼到文本框內,這個可以通過DataObject的附加事件Pasting來實現,代碼如下:
1 public NumericTextBox() 2 { 3 DataObject.AddPastingHandler(this, Text_Pasting); 4 } 5 6 private void Text_Pasting(object sender, DataObjectPastingEventArgs e) 7 { 8 //禁止Pasting 9 e.CancelCommand(); 10 }
“意外”的是由於在PreviewKeyDown中 對組合鍵進行了判斷,所以就不需要這個Pasting事件了。
在很多業務需求中需要這個TextBox有個最大值和最小值,我個人的做法是在TextChanged事件中進行判斷,這個就沒有辦法避免類型轉換了,代碼如下:
1 protected override void OnTextChanged(TextChangedEventArgs e) 2 { 3 if (_isReentry) 4 { 5 SelectionStart = _index; 6 return; 7 } 8 _isReentry = true; 9 Int32 temp = 0; 10 if (Int32.TryParse(Text, out temp)) 11 { 12 if (temp > Maximum || temp < Minimum) 13 { 14 temp = temp > Maximum ? Maximum : Minimum; 15 _index = SelectionStart; 16 } 17 Text = temp.ToString(); 18 } 19 //類型不正確或者超長會導致轉換失敗 20 else 21 { 22 Text = Int32.MaxValue.ToString(); 23 } 24 _isReentry = false; 25 }
兩個局部變量為:
1 private Int32 _index; //光標位置 2 private bool _isReentry; //標識TextChanged事件是否重入
如果有什么更好的想法,歡迎指教。