非原创,整理之前的代码的时候找出来的,可用,与大家分享一下!

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

使用:

  1. <Controls:NumericBox Grid.Column="3" Grid.Row="11"
  2. Width="200" Height="30" Text="{Binding old,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
  3. CustomTextWrapping="NoWrap" CustomTextHeight="26" CustomTextWidth="170"
  4. BgForeground="{StaticResource DialogTextBgForeground}"
  5. CustomBorderColor="{StaticResource DialogTextBorderColor}" CustomBgColor="{StaticResource DialogTextBgColor}" >
  6. <i:Interaction.Behaviors>
  7. <Controls:TextBoxFilterBehavior TextBoxFilterOptions="Numeric"/> <!--可以选择输入数字,小数点等-->
  8. </i:Interaction.Behaviors>
  9. </Controls:NumericBox>

WPF 自定义TextBox,可控制键盘输入内容的更多相关文章

  1. WPF自定义TextBox及ScrollViewer

    原文:WPF自定义TextBox及ScrollViewer 寒假过完,在家真心什么都做不了,可能年龄大了,再想以前那样能专心坐下来已经不行了.回来第一件事就是改了项目的一个bug,最近又新增了一个新的 ...

  2. 在ie9下在textbox框里面输入内容按enter键会触发按钮的事件

    问题 在ie下,如果存在有button标签,如果在textbox里面输入内容,按下enter键,则会触发第一个按钮的click事件,经过测试,在IE10以及以下的都存在这个问题 原因 浏览器默认行为不 ...

  3. WPF 自定义TextBox带水印控件,可设置圆角

    一.简单设置水印TextBox控件,废话不多说看代码: <TextBox TextWrapping="Wrap" Margin="10" Height=& ...

  4. WPF 中textBox实现只输入数字

    刚学到 通过本方法可以使文本框只能输入或复制入数字  对于数量类输入文本框比较有用 金额类只需小改动也可实现 以TextBox txtCount为例 添加TextChanged事件 代码如下 priv ...

  5. WPF 自定义TextBox

    1.TextBox前加图标. 效果: <TextBox Width="300" Height="30" Style="{StaticResour ...

  6. WPF 限制Textbox输入的内容

    限制文本框TextBox的输入内容,在很多场景都有应用.举个例子,现在文本框中,只能输入0.1.2.3.4.5.6.7.8.9.“|”这11个字符. 限制输入0-9很容易实现,关键是这个“|”符号.它 ...

  7. Ajax实现在textbox中输入内容,动态从数据库中模糊查询显示到下拉框中

    功能:在textbox中输入内容,动态从数据库模糊查询显示到下拉框中,以供选择 1.建立一aspx页面,html代码 <HTML> <HEAD> <title>We ...

  8. WPF中TextBox限制输入不起作用的问题

    最近再用textbox做限制输入时遇到一个莫名其妙的问题: 首先看代码: <TextBox  Name="txtip1" Height="40" Widt ...

  9. VC++6.0/MFC 自定义edit 限制输入内容 响应复制粘贴全选剪切的功能

    Ctrl组合键ASCII码 ^Z代表Ctrl+z                     ASCII值 控制字符  ASCII值 控制字符  ASCII值 控制字符  ASCII值 控制字符0(00) ...

随机推荐

  1. 【python】函数之内置函数

    Python基础 内置函数 今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是 ...

  2. [转载] Android随笔之——PackageManager详解

    本文转载自: http://www.cnblogs.com/travellife/p/3932823.html 参考:http://www.cnblogs.com/xingfuzzhd/p/33745 ...

  3. tmux 操作

    http://www.cnblogs.com/congbo/archive/2012/08/30/2649420.html https://www.digitalocean.com/community ...

  4. DataInputStream和DataOutputStream

    import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInp ...

  5. ZT 螨虫的话就不要跟狗多接触,狗的寄生虫很多,还有草地,

    病情分析:过敏是治不好的,只能做到避免接触.指导意见:螨虫的话就不要跟狗多接触,狗的寄生虫很多,还有草地,尤其是狗经常去的地方,草地就是螨虫的传播介质.你是过敏性体质除了被免 过敏性源外,还要增强体质 ...

  6. I/O复用

    1.I/O模型 一个输入操作通常包括两个不同阶段:等待数据准备好:从内核到进程拷贝数据. 阻塞I/O模型 非阻塞I/O模型 I/O复用模型:内核发现进程指定的一个或多个I/O条件就绪,它就通知进程,由 ...

  7. 让Asp.net mvc WebAPI 支持OData协议进行分页查询操作

    这是我在用Asp.net mvc WebAPI 支持 OData协议 做分页查询服务时的 个人拙笔. 代码已经开发到oschina上.有兴趣的朋友可以看看,欢迎大家指出不足之处. 看过了园子里的几篇关 ...

  8. XE3随笔17:实例 - 模拟 Google 搜索

    本例测试效果图: 代码文件: unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics ...

  9. Ceph剖析:线程池实现

    线程池ThreadPool的实现符合生产者-消费者模型,这个模型解除生产者消费者间的耦合关系,生产者可以专注处理制造产品的逻辑而不用关心产品的消费,消费者亦然.当然,生产者消费者之间需要一个连接的纽带 ...

  10. HTML5新增的属性

    关于html5新增的属性: HTML5现在已经不是SGML的子集,主要是增加了关于图像,位置,存储,多任务等功能. 绘画CANVAS; 用于播放媒体的video和audio元素: 本地离线存储loca ...