非原創,整理以前的代碼的時候找出來的,可用,與你們分享一下!git
1 public class NumbericBoxWithZero : NumericBox 2 { 3 public NumbericBoxWithZero() 4 : base() 5 { 6 7 8 } 9 protected override void SetTextAndSelection(string text) 10 { 11 if (text.IndexOf('.') == -1) 12 { 13 text = text + ".00"; 14 } 15 else 16 { 17 if (text.IndexOf('.') != text.Length - 1) 18 { 19 string front = text.Substring(0,text.IndexOf('.')); 20 string back = text.Substring(text.IndexOf('.') + 1, text.Length - text.IndexOf('.') - 1); 21 if(back != "00") 22 text = string.Format("{0}.{1:d2}",front,int.Parse(back)); 23 } 24 } 25 base.SetTextAndSelection(text); 26 } 27 } 28 /// <summary> 29 /// NumericBox功能設計 30 /// 只能輸入0-9的數字和至多一個小數點; 31 ///可以屏蔽經過非正常途徑的不正確輸入(輸入法,粘貼等); 32 ///可以控制小數點後的最大位數,超出位數則沒法繼續輸入; 33 ///可以選擇當小數點數位數不足時是否補0; 34 ///去除開頭部分多餘的0(爲方便處理,當在開頭部分輸入0時,自動在其後添加一個小數點); 35 ///因爲只能輸入一個小數點,當在已有的小數點前再次按下小數點,可以跳太小數點; 36 /// </summary> 37 public class NumericBox : TextBox 38 { 39 #region Dependency Properties 40 /// <summary> 41 /// 最大小數點位數 42 /// </summary> 43 public int MaxFractionDigits 44 { 45 get { return (int)GetValue(MaxFractionDigitsProperty); } 46 set { SetValue(MaxFractionDigitsProperty, value); } 47 } 48 // Using a DependencyProperty as the backing store for MaxFractionDigits. This enables animation, styling, binding, etc... 49 public static readonly DependencyProperty MaxFractionDigitsProperty = 50 DependencyProperty.Register("MaxFractionDigits", typeof(int), typeof(NumericBox), new PropertyMetadata(2)); 51 52 /// <summary> 53 /// 不足位數是否補零 54 /// </summary> 55 public bool IsPadding 56 { 57 get { return (bool)GetValue(IsPaddingProperty); } 58 set { SetValue(IsPaddingProperty, value); } 59 } 60 // Using a DependencyProperty as the backing store for IsPadding. This enables animation, styling, binding, etc... 61 public static readonly DependencyProperty IsPaddingProperty = 62 DependencyProperty.Register("IsPadding", typeof(bool), typeof(NumericBox), new PropertyMetadata(true)); 63 64 #endregion 65 66 public NumericBox() 67 { 68 TextBoxFilterBehavior behavior = new TextBoxFilterBehavior(); 69 behavior.TextBoxFilterOptions = TextBoxFilterOptions.Numeric | TextBoxFilterOptions.Dot; 70 Interaction.GetBehaviors(this).Add(behavior); 71 this.TextChanged += new TextChangedEventHandler(NumericBox_TextChanged); 72 } 73 74 /// <summary> 75 /// 設置Text文本以及光標位置 76 /// </summary> 77 /// <param name="text"></param> 78 protected virtual void SetTextAndSelection(string text) 79 { 80 //保存光標位置 81 int selectionIndex = this.SelectionStart; 82 this.Text = text; 83 //恢復光標位置 系統會自動處理光標位置超出文本長度的狀況 84 this.SelectionStart = selectionIndex; 85 } 86 87 /// <summary> 88 /// 去掉開頭部分多餘的0 89 /// </summary> 90 private void TrimZeroStart() 91 { 92 string resultText = this.Text; 93 //計算開頭部分0的個數 94 int zeroCount = 0; 95 foreach (char c in this.Text) 96 { 97 if (c == '0') { zeroCount++; } 98 else { break; } 99 } 100 101 //當前文本中包含小數點 102 if (this.Text.Contains('.')) 103 { 104 //0後面跟的不是小數點,則刪除所有的0 105 if (this.Text[zeroCount] != '.') 106 { 107 resultText = this.Text.TrimStart('0'); 108 } 109 //不然,保留一個0 110 else if (zeroCount > 1) 111 { 112 resultText = this.Text.Substring(zeroCount - 1); 113 } 114 } 115 //當前文本中不包含小數點,則保留一個0,並在其後加一個小數點,並將光標設置到小數點前 116 else if (zeroCount > 0) 117 { 118 resultText = "0." + this.Text.TrimStart('0'); 119 this.SelectionStart = 1; 120 } 121 122 SetTextAndSelection(resultText); 123 } 124 125 void NumericBox_TextChanged(object sender, TextChangedEventArgs e) 126 { 127 int decimalIndex = this.Text.IndexOf('.'); 128 if (decimalIndex >= 0) 129 { 130 //小數點後的位數 131 int lengthAfterDecimal = this.Text.Length - decimalIndex - 1; 132 if (lengthAfterDecimal > MaxFractionDigits) 133 { 134 SetTextAndSelection(this.Text.Substring(0, this.Text.Length - (lengthAfterDecimal - MaxFractionDigits))); 135 } 136 else if (IsPadding) 137 { 138 SetTextAndSelection(this.Text.PadRight(this.Text.Length + MaxFractionDigits - lengthAfterDecimal, '0')); 139 } 140 } 141 TrimZeroStart(); 142 } 143 } 144 /// <summary> 145 /// TextBox篩選行爲,過濾不須要的按鍵 146 /// </summary> 147 public class TextBoxFilterBehavior : Behavior<TextBox> 148 { 149 private string _prevText = string.Empty; 150 public TextBoxFilterBehavior() 151 { 152 } 153 #region Dependency Properties 154 /// <summary> 155 /// TextBox篩選選項,這裏選擇的爲過濾後剩下的按鍵 156 /// 控制鍵不參與篩選,能夠多選組合 157 /// </summary> 158 public TextBoxFilterOptions TextBoxFilterOptions 159 { 160 get { return (TextBoxFilterOptions)GetValue(TextBoxFilterOptionsProperty); } 161 set { SetValue(TextBoxFilterOptionsProperty, value); } 162 } 163 164 // Using a DependencyProperty as the backing store for TextBoxFilterOptions. This enables animation, styling, binding, etc... 165 public static readonly DependencyProperty TextBoxFilterOptionsProperty = 166 DependencyProperty.Register("TextBoxFilterOptions", typeof(TextBoxFilterOptions), typeof(TextBoxFilterBehavior), new PropertyMetadata(TextBoxFilterOptions.None)); 167 #endregion 168 169 protected override void OnAttached() 170 { 171 base.OnAttached(); 172 this.AssociatedObject.KeyDown += new KeyEventHandler(AssociatedObject_KeyDown); 173 this.AssociatedObject.TextChanged += new TextChangedEventHandler(AssociatedObject_TextChanged); 174 } 175 176 protected override void OnDetaching() 177 { 178 base.OnDetaching(); 179 this.AssociatedObject.KeyDown -= new KeyEventHandler(AssociatedObject_KeyDown); 180 this.AssociatedObject.TextChanged -= new TextChangedEventHandler(AssociatedObject_TextChanged); 181 } 182 183 #region Events 184 185 /// <summary> 186 /// 處理經過其它手段進行的輸入 187 /// </summary> 188 /// <param name="sender"></param> 189 /// <param name="e"></param> 190 void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e) 191 { 192 //若是符合規則,就保存下來 193 if (IsValidText(this.AssociatedObject.Text)) 194 { 195 _prevText = this.AssociatedObject.Text; 196 } 197 //若是不符合規則,就恢復爲以前保存的值 198 else 199 { 200 int selectIndex = this.AssociatedObject.SelectionStart - (this.AssociatedObject.Text.Length - _prevText.Length); 201 this.AssociatedObject.Text = _prevText; 202 203 if (selectIndex < 0) 204 selectIndex = 0; 205 206 this.AssociatedObject.SelectionStart = selectIndex; 207 } 208 209 } 210 211 /// <summary> 212 /// 處理按鍵產生的輸入 213 /// </summary> 214 /// <param name="sender"></param> 215 /// <param name="e"></param> 216 void AssociatedObject_KeyDown(object sender, KeyEventArgs e) 217 { 218 bool handled = true; 219 //不進行過濾 220 if (TextBoxFilterOptions == TextBoxFilterOptions.None || 221 KeyboardHelper.IsControlKeys(e.Key)) 222 { 223 handled = false; 224 } 225 //數字鍵 226 if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Numeric)) 227 { 228 handled = !KeyboardHelper.IsDigit(e.Key); 229 } 230 //小數點 231 //if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Dot)) 232 //{ 233 // handled = !(KeyboardHelper.IsDot(e.Key, e.PlatformKeyCode) && !_prevText.Contains(".")); 234 // if (KeyboardHelper.IsDot(e.Key, e.PlatformKeyCode) && _prevText.Contains(".")) 235 // { 236 // //若是輸入位置的下一個就是小數點,則將光標跳到小數點後面 237 // if (this.AssociatedObject.SelectionStart< this.AssociatedObject.Text.Length && _prevText[this.AssociatedObject.SelectionStart] == '.') 238 // { 239 // this.AssociatedObject.SelectionStart++; 240 // } 241 // } 242 //} 243 if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Dot)) 244 { 245 handled = !(KeyboardHelper.IsDot(e.Key) && !_prevText.Contains(".")); 246 if (KeyboardHelper.IsDot(e.Key) && _prevText.Contains(".")) 247 { 248 //若是輸入位置的下一個就是小數點,則將光標跳到小數點後面 249 if (this.AssociatedObject.SelectionStart < this.AssociatedObject.Text.Length && _prevText[this.AssociatedObject.SelectionStart] == '.') 250 { 251 this.AssociatedObject.SelectionStart++; 252 } 253 } 254 } 255 //字母 256 if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Character)) 257 { 258 handled = !KeyboardHelper.IsDot(e.Key); 259 } 260 e.Handled = handled; 261 } 262 263 #endregion 264 265 #region Private Methods 266 /// <summary> 267 /// 判斷是否符合規則 268 /// </summary> 269 /// <param name="c"></param> 270 /// <returns></returns> 271 private bool IsValidChar(char c) 272 { 273 if (TextBoxFilterOptions == TextBoxFilterOptions.None) 274 { 275 return true; 276 } 277 else if (TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Numeric) && 278 '0' <= c && c <= '9') 279 { 280 return true; 281 } 282 else if (TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Dot) && 283 c == '.') 284 { 285 return true; 286 } 287 else if (TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Character)) 288 { 289 if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) 290 { 291 return true; 292 } 293 } 294 return false; 295 } 296 297 /// <summary> 298 /// 判斷文本是否符合規則 299 /// </summary> 300 /// <param name="text"></param> 301 /// <returns></returns> 302 private bool IsValidText(string text) 303 { 304 //只能有一個小數點 305 if (text.IndexOf('.') != text.LastIndexOf('.')) 306 { 307 return false; 308 } 309 foreach (char c in text) 310 { 311 if (!IsValidChar(c)) 312 { 313 return false; 314 } 315 } 316 return true; 317 } 318 #endregion 319 } 320 /// <summary> 321 /// TextBox篩選選項 322 /// </summary> 323 [Flags] 324 public enum TextBoxFilterOptions 325 { 326 /// <summary> 327 /// 不採用任何篩選 328 /// </summary> 329 None = 0, 330 /// <summary> 331 /// 數字類型不參與篩選 332 /// </summary> 333 Numeric = 1, 334 /// <summary> 335 /// 字母類型不參與篩選 336 /// </summary> 337 Character = 2, 338 /// <summary> 339 /// 小數點不參與篩選 340 /// </summary> 341 Dot = 4, 342 /// <summary> 343 /// 其它類型不參與篩選 344 /// </summary> 345 Other = 8 346 } 347 348 /// <summary> 349 /// TextBox篩選選項枚舉擴展方法 350 /// </summary> 351 public static class TextBoxFilterOptionsExtension 352 { 353 /// <summary> 354 /// 在所有的選項中是否包含指定的選項 355 /// </summary> 356 /// <param name="allOptions">全部的選項</param> 357 /// <param name="option">指定的選項</param> 358 /// <returns></returns> 359 public static bool ContainsOption(this TextBoxFilterOptions allOptions, TextBoxFilterOptions option) 360 { 361 return (allOptions & option) == option; 362 } 363 } 364 /// <summary> 365 /// 鍵盤操做幫助類 366 /// </summary> 367 public class KeyboardHelper 368 { 369 /// <summary> 370 /// 鍵盤上的句號鍵 371 /// </summary> 372 public const int OemPeriod = 190; 373 374 #region Fileds 375 376 /// <summary> 377 /// 控制鍵 378 /// </summary> 379 private static readonly List<Key> _controlKeys = new List<Key> 380 { 381 Key.Back, 382 Key.CapsLock, 383 //Key.Ctrl, 384 Key.Down, 385 Key.End, 386 Key.Enter, 387 Key.Escape, 388 Key.Home, 389 Key.Insert, 390 Key.Left, 391 Key.PageDown, 392 Key.PageUp, 393 Key.Right, 394 //Key.Shift, 395 Key.Tab, 396 Key.Up 397 }; 398 399 #endregion 400 401 /// <summary> 402 /// 是不是數字鍵 403 /// </summary> 404 /// <param name="key">按鍵</param> 405 /// <returns></returns> 406 public static bool IsDigit(Key key) 407 { 408 bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0; 409 bool retVal; 410 //按住shift鍵後,數字鍵並非數字鍵 411 if (key >= Key.D0 && key <= Key.D9 && !shiftKey) 412 { 413 retVal = true; 414 } 415 else 416 { 417 retVal = key >= Key.NumPad0 && key <= Key.NumPad9; 418 } 419 return retVal; 420 } 421 422 /// <summary> 423 /// 是不是控制鍵 424 /// </summary> 425 /// <param name="key">按鍵</param> 426 /// <returns></returns> 427 public static bool IsControlKeys(Key key) 428 { 429 return _controlKeys.Contains(key); 430 } 431 432 /// <summary> 433 /// 是不是小數點 434 /// Silverlight中沒法識別問號左邊的那個小數點鍵 435 /// 只能識別小鍵盤中的小數點 436 /// </summary> 437 /// <param name="key">按鍵</param> 438 /// <returns></returns> 439 public static bool IsDot(Key key) 440 { 441 bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0; 442 bool flag = false; 443 if (key == Key.Decimal) 444 { 445 flag = true; 446 } 447 if (key == Key.OemPeriod && !shiftKey) 448 { 449 flag = true; 450 } 451 return flag; 452 } 453 454 /// <summary> 455 /// 是不是小數點 456 /// </summary> 457 /// <param name="key">按鍵</param> 458 /// <param name="keyCode">平臺相關的按鍵代碼</param> 459 /// <returns></returns> 460 public static bool IsDot(Key key, int keyCode) 461 { 462 463 //return IsDot(key) || (key == Key.Unknown && keyCode == OemPeriod); 464 return IsDot(key) || (keyCode == OemPeriod); 465 } 466 467 /// <summary> 468 /// 是不是字母鍵 469 /// </summary> 470 /// <param name="key">按鍵</param> 471 /// <returns></returns> 472 public static bool IsCharacter(Key key) 473 { 474 return key >= Key.A && key <= Key.Z; 475 } 476 }
使用:app
<Controls:NumericBox Grid.Column="3" Grid.Row="11" Width="200" Height="30" Text="{Binding old,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" CustomTextWrapping="NoWrap" CustomTextHeight="26" CustomTextWidth="170" BgForeground="{StaticResource DialogTextBgForeground}" CustomBorderColor="{StaticResource DialogTextBorderColor}" CustomBgColor="{StaticResource DialogTextBgColor}" > <i:Interaction.Behaviors> <Controls:TextBoxFilterBehavior TextBoxFilterOptions="Numeric"/> <!--能夠選擇輸入數字,小數點等--> </i:Interaction.Behaviors> </Controls:NumericBox>