WPF 自定义TextBox,可控制键盘输入内容

摘要:
非原创,在整理之前的代码时发现,可用,与您共享!

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

WPF 自定义TextBox,可控制键盘输入内容第1张WPF 自定义TextBox,可控制键盘输入内容第2张
  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     }
View Code

使用:

 <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>

免责声明:文章转载自《WPF 自定义TextBox,可控制键盘输入内容》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇.NET 配置文件简单使用spyder使用IPython的ipdb调试下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WPF数据双向绑定

设置双向绑定,首先控件要绑定的对象要先继承一个接口: INotifyPropertyChanged 然后对应被绑定的属性增加代码如下: 意思就是当Age这个属性变化时,要通知监听它变化的人。 即:PropertyChanged(this, new PropertyChangedEventArgs("Age")) ,PropertyChangedEvent...

走进WPF之UI布局

一个成功的软件,离不开人性化的UI设计,如何抓住用户第一视觉,让用户产生依赖感,合适优雅的布局必不可少。本文以一些简单的小例子,简述WPF中布局面板控件的使用,仅供学习分享使用,如有不足之处,还请指正。 涉及知识点 在WPF中,关于布局面板控件,主要有以下几种: StackPanel:栈面板,可以将元素排列成一行或者一列。其特点是:每个元素各占一行或者一...

WPF TextBox/TextBlock 文本超出显示时,文本靠右显示

文本框显示 文本框正常显示: 文本框超出区域显示: 实现方案 判断文本框是否超出区域 请见《TextBlock IsTextTrimmed 判断文本是否超出》 设置文本布局显示 1. FlowDirection 当文本超出显示区域时,设置FlowDirection靠右显示 下面是封装的附加属性ScrollEndWhenTextTrimmed 1...

WPF 导出EXCEL 方法

是用WPF将数据导出成EXCEL其实和其他.NET应用是相通的,ASP.NET也好WINFORM也好,都是用相同的方法实现,唯一不同的是ASP.NET中可能会存在用户权限的问题,毕竟ASP.NET的执行用户是IIS指定的用户而不是默认的系统用户。 具体实现方法如下,代码中使用完整的名称空间,便于理解 第一步,不许引用Excel的程序集,不同于网上其他文章,...

WPF 自定义ColorDialog DropDownCustomColorPicker

今天分享一个 WPF 版的ColorDialog,该控件源自 这里,不过笔者已经该控件做了大量的修改工作,以适应自己的产品需求,闲话少说,先看看效果图: 1、DropDownCustomColorPicker 效果图 先看原项目的(喜欢这种方式的,请到 这里下载源码 ) 被笔者修改之后的效果图: 二、DropDownCustomColorPicker...

WPF开发进阶

前一篇 简单的介绍了Fody/PropertyChanged的使用方法, 这一篇,我们详细介绍它的一些比较重要的特性和规则 1. Attributes 通过在类或属性上标记这些特性,可以在编译代码时,注入特定的功能 ImplementPropertyChangedAttribute 为类标记此特性,可以实现INotifyPropertyChanged接口...