WPF中限制TextBox輸入


(一)這今天做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>

(五)代碼下載

 代碼

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM