非原创,整理之前的代码的时候找出来的,可用,与大家分享一下!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
使用:
<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>