(一)這今天做wpf項目的時候,有關TextBox輸入驗證的問題。關於驗證
(1)輸入的時候做到有效數據的有效輸入
(2)輸入后再操作時候做檢查,並彈出對話框提示。
我跟傾向於在輸入的時候做到限制的有效輸入
在項目中碰到的問題。
(1)輸入框只能輸入整數
(2)輸入框輸入的含小數位數最大位數為4位
(二)下考了如下鏈接。
(1)大氣象學習園地的
Silverlight限制TextBox只能輸入整數或者小數
(2)yingql的
Silverlight開發中的疑難雜症-控件設計篇-如何實現一個NumericBox(上)
Silverlight開發中的疑難雜症-控件設計篇-如何實現一個NumericBox(下)
Silverlight開發中的疑難雜症-如何通過代碼附加Behavior
(三)基於TextBox的自定義控件NumericBox
注意點,由於涉及到Behavior,需要引用Blend中System.Windows.Interactivity.dll
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Input; using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; namespace NumericBoxDemo { /// <summary> /// NumericBox功能設計 /// 只能輸入0-9的數字和至多一個小數點; ///能夠屏蔽通過非正常途徑的不正確輸入(輸入法,粘貼等); ///能夠控制小數點后的最大位數,超出位數則無法繼續輸入; ///能夠選擇當小數點數位數不足時是否補0; ///去除開頭部分多余的0(為方便處理,當在開頭部分輸入0時,自動在其后添加一個小數點); ///由於只能輸入一個小數點,當在已有的小數點前再次按下小數點,能夠跳過小數點; /// </summary> public class NumericBox : TextBox { #region Dependency Properties /// <summary> /// 最大小數點位數 /// </summary> public int MaxFractionDigits { get { return (int)GetValue(MaxFractionDigitsProperty); } set { SetValue(MaxFractionDigitsProperty, value); } } // Using a DependencyProperty as the backing store for MaxFractionDigits. This enables animation, styling, binding, etc... public static readonly DependencyProperty MaxFractionDigitsProperty = DependencyProperty.Register("MaxFractionDigits", typeof(int), typeof(NumericBox), new PropertyMetadata(2)); /// <summary> /// 不足位數是否補零 /// </summary> public bool IsPadding { get { return (bool)GetValue(IsPaddingProperty); } set { SetValue(IsPaddingProperty, value); } } // Using a DependencyProperty as the backing store for IsPadding. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsPaddingProperty = DependencyProperty.Register("IsPadding", typeof(bool), typeof(NumericBox), new PropertyMetadata(true)); #endregion public NumericBox() { TextBoxFilterBehavior behavior = new TextBoxFilterBehavior(); behavior.TextBoxFilterOptions = TextBoxFilterOptions.Numeric | TextBoxFilterOptions.Dot; Interaction.GetBehaviors(this).Add(behavior); this.TextChanged += new TextChangedEventHandler(NumericBox_TextChanged); } /// <summary> /// 設置Text文本以及光標位置 /// </summary> /// <param name="text"></param> private void SetTextAndSelection(string text) { //保存光標位置 int selectionIndex = this.SelectionStart; this.Text = text; //恢復光標位置 系統會自動處理光標位置超出文本長度的情況 this.SelectionStart = selectionIndex; } /// <summary> /// 去掉開頭部分多余的0 /// </summary> private void TrimZeroStart() { string resultText = this.Text; //計算開頭部分0的個數 int zeroCount = 0; foreach (char c in this.Text) { if (c == '0') { zeroCount++; } else { break; } } //當前文本中包含小數點 if (this.Text.Contains('.')) { //0后面跟的不是小數點,則刪除全部的0 if (this.Text[zeroCount] != '.') { resultText = this.Text.TrimStart('0'); } //否則,保留一個0 else if (zeroCount > 1) { resultText = this.Text.Substring(zeroCount - 1); } } //當前文本中不包含小數點,則保留一個0,並在其后加一個小數點,並將光標設置到小數點前 else if (zeroCount > 0) { resultText = "0." + this.Text.TrimStart('0'); this.SelectionStart = 1; } SetTextAndSelection(resultText); } void NumericBox_TextChanged(object sender, TextChangedEventArgs e) { int decimalIndex = this.Text.IndexOf('.'); if (decimalIndex >= 0) { //小數點后的位數 int lengthAfterDecimal = this.Text.Length - decimalIndex - 1; if (lengthAfterDecimal > MaxFractionDigits) { SetTextAndSelection(this.Text.Substring(0, this.Text.Length - (lengthAfterDecimal - MaxFractionDigits))); } else if (IsPadding) { SetTextAndSelection(this.Text.PadRight(this.Text.Length + MaxFractionDigits - lengthAfterDecimal, '0')); } } TrimZeroStart(); } } /// <summary> /// TextBox篩選行為,過濾不需要的按鍵 /// </summary> public class TextBoxFilterBehavior : Behavior<TextBox> { private string _prevText = string.Empty; public TextBoxFilterBehavior() { } #region Dependency Properties /// <summary> /// TextBox篩選選項,這里選擇的為過濾后剩下的按鍵 /// 控制鍵不參與篩選,可以多選組合 /// </summary> public TextBoxFilterOptions TextBoxFilterOptions { get { return (TextBoxFilterOptions)GetValue(TextBoxFilterOptionsProperty); } set { SetValue(TextBoxFilterOptionsProperty, value); } } // Using a DependencyProperty as the backing store for TextBoxFilterOptions. This enables animation, styling, binding, etc... public static readonly DependencyProperty TextBoxFilterOptionsProperty = DependencyProperty.Register("TextBoxFilterOptions", typeof(TextBoxFilterOptions), typeof(TextBoxFilterBehavior), new PropertyMetadata(TextBoxFilterOptions.None)); #endregion protected override void OnAttached() { base.OnAttached(); this.AssociatedObject.KeyDown += new KeyEventHandler(AssociatedObject_KeyDown); this.AssociatedObject.TextChanged += new TextChangedEventHandler(AssociatedObject_TextChanged); } protected override void OnDetaching() { base.OnDetaching(); this.AssociatedObject.KeyDown -= new KeyEventHandler(AssociatedObject_KeyDown); this.AssociatedObject.TextChanged -= new TextChangedEventHandler(AssociatedObject_TextChanged); } #region Events /// <summary> /// 處理通過其它手段進行的輸入 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e) { //如果符合規則,就保存下來 if (IsValidText(this.AssociatedObject.Text)) { _prevText = this.AssociatedObject.Text; } //如果不符合規則,就恢復為之前保存的值 else { int selectIndex = this.AssociatedObject.SelectionStart - (this.AssociatedObject.Text.Length - _prevText.Length); this.AssociatedObject.Text = _prevText; this.AssociatedObject.SelectionStart = selectIndex; } } /// <summary> /// 處理按鍵產生的輸入 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void AssociatedObject_KeyDown(object sender, KeyEventArgs e) { bool handled = true; //不進行過濾 if (TextBoxFilterOptions == TextBoxFilterOptions.None || KeyboardHelper.IsControlKeys(e.Key)) { handled = false; } //數字鍵 if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Numeric)) { handled = !KeyboardHelper.IsDigit(e.Key); } //小數點 //if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Dot)) //{ // handled = !(KeyboardHelper.IsDot(e.Key, e.PlatformKeyCode) && !_prevText.Contains(".")); // if (KeyboardHelper.IsDot(e.Key, e.PlatformKeyCode) && _prevText.Contains(".")) // { // //如果輸入位置的下一個就是小數點,則將光標跳到小數點后面 // if (this.AssociatedObject.SelectionStart< this.AssociatedObject.Text.Length && _prevText[this.AssociatedObject.SelectionStart] == '.') // { // this.AssociatedObject.SelectionStart++; // } // } //} if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Dot)) { handled = !(KeyboardHelper.IsDot(e.Key) && !_prevText.Contains(".")); if (KeyboardHelper.IsDot(e.Key) && _prevText.Contains(".")) { //如果輸入位置的下一個就是小數點,則將光標跳到小數點后面 if (this.AssociatedObject.SelectionStart < this.AssociatedObject.Text.Length && _prevText[this.AssociatedObject.SelectionStart] == '.') { this.AssociatedObject.SelectionStart++; } } } //字母 if (handled && TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Character)) { handled = !KeyboardHelper.IsDot(e.Key); } e.Handled = handled; } #endregion #region Private Methods /// <summary> /// 判斷是否符合規則 /// </summary> /// <param name="c"></param> /// <returns></returns> private bool IsValidChar(char c) { if (TextBoxFilterOptions == TextBoxFilterOptions.None) { return true; } else if (TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Numeric) && '0' <= c && c <= '9') { return true; } else if (TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Dot) && c == '.') { return true; } else if (TextBoxFilterOptions.ContainsOption(TextBoxFilterOptions.Character)) { if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) { return true; } } return false; } /// <summary> /// 判斷文本是否符合規則 /// </summary> /// <param name="text"></param> /// <returns></returns> private bool IsValidText(string text) { //只能有一個小數點 if (text.IndexOf('.') != text.LastIndexOf('.')) { return false; } foreach (char c in text) { if (!IsValidChar(c)) { return false; } } return true; } #endregion } /// <summary> /// TextBox篩選選項 /// </summary> [Flags] public enum TextBoxFilterOptions { /// <summary> /// 不采用任何篩選 /// </summary> None = 0, /// <summary> /// 數字類型不參與篩選 /// </summary> Numeric = 1, /// <summary> /// 字母類型不參與篩選 /// </summary> Character = 2, /// <summary> /// 小數點不參與篩選 /// </summary> Dot = 4, /// <summary> /// 其它類型不參與篩選 /// </summary> Other = 8 } /// <summary> /// TextBox篩選選項枚舉擴展方法 /// </summary> public static class TextBoxFilterOptionsExtension { /// <summary> /// 在全部的選項中是否包含指定的選項 /// </summary> /// <param name="allOptions">所有的選項</param> /// <param name="option">指定的選項</param> /// <returns></returns> public static bool ContainsOption(this TextBoxFilterOptions allOptions, TextBoxFilterOptions option) { return (allOptions & option) == option; } } /// <summary> /// 鍵盤操作幫助類 /// </summary> public class KeyboardHelper { /// <summary> /// 鍵盤上的句號鍵 /// </summary> public const int OemPeriod = 190; #region Fileds /// <summary> /// 控制鍵 /// </summary> private static readonly List<Key> _controlKeys = new List<Key> { Key.Back, Key.CapsLock, //Key.Ctrl, Key.Down, Key.End, Key.Enter, Key.Escape, Key.Home, Key.Insert, Key.Left, Key.PageDown, Key.PageUp, Key.Right, //Key.Shift, Key.Tab, Key.Up }; #endregion /// <summary> /// 是否是數字鍵 /// </summary> /// <param name="key">按鍵</param> /// <returns></returns> public static bool IsDigit(Key key) { bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0; bool retVal; //按住shift鍵后,數字鍵並不是數字鍵 if (key >= Key.D0 && key <= Key.D9 && !shiftKey) { retVal = true; } else { retVal = key >= Key.NumPad0 && key <= Key.NumPad9; } return retVal; } /// <summary> /// 是否是控制鍵 /// </summary> /// <param name="key">按鍵</param> /// <returns></returns> public static bool IsControlKeys(Key key) { return _controlKeys.Contains(key); } /// <summary> /// 是否是小數點 /// Silverlight中無法識別問號左邊的那個小數點鍵 /// 只能識別小鍵盤中的小數點 /// </summary> /// <param name="key">按鍵</param> /// <returns></returns> public static bool IsDot(Key key) { bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0; bool flag=false; if(key==Key.Decimal) { flag=true; } if(key==Key.OemPeriod && !shiftKey) { flag = true; } return flag; } /// <summary> /// 是否是小數點 /// </summary> /// <param name="key">按鍵</param> /// <param name="keyCode">平台相關的按鍵代碼</param> /// <returns></returns> public static bool IsDot(Key key, int keyCode) { //return IsDot(key) || (key == Key.Unknown && keyCode == OemPeriod); return IsDot(key) || (keyCode == OemPeriod); } /// <summary> /// 是否是字母鍵 /// </summary> /// <param name="key">按鍵</param> /// <returns></returns> public static bool IsCharacter(Key key) { return key >= Key.A && key <= Key.Z; } } }
(四)使用自定義控件
使用行為分別可以指定 “Numeric” ,"Dot","Charcter"等.默認Numeric | Dot
注意點用添加 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"命名空間
<Window x:Class="NumericBoxDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:local="clr-namespace:NumericBoxDemo" Title="MainWindow" Height="350" Width="525"> <Grid> <StackPanel> <local:NumericBox Width="200" Height="30" MaxFractionDigits="4" IsPadding="False"> <i:Interaction.Behaviors> <local:TextBoxFilterBehavior TextBoxFilterOptions="Numeric"/> </i:Interaction.Behaviors> </local:NumericBox> <local:NumericBox Width="200" Height="30" MaxFractionDigits="4" IsPadding="False"> <i:Interaction.Behaviors> <local:TextBoxFilterBehavior TextBoxFilterOptions="Dot" /> </i:Interaction.Behaviors> </local:NumericBox> <local:NumericBox Width="200" Height="30" MaxFractionDigits="4" IsPadding="False"> <i:Interaction.Behaviors> <local:TextBoxFilterBehavior TextBoxFilterOptions="Character" /> </i:Interaction.Behaviors> </local:NumericBox> <local:NumericBox Width="200" Height="30" MaxFractionDigits="4" IsPadding="False"> </local:NumericBox> </StackPanel> </Grid> </Window>
(五)代碼下載