How do I get a TextBox to only accept numeric input in WPF?

后端 未结 30 2341
悲哀的现实
悲哀的现实 2020-11-22 03:40

I\'m looking to accept digits and the decimal point, but no sign.

I\'ve looked at samples using the NumericUpDown control for Windows Forms, and this sample of a Num

30条回答
  •  情话喂你
    2020-11-22 04:01

    Another approach will be using an attached behavior, I implemented my custom TextBoxHelper class, which can be used on textboxes all over my project. Because I figured that subscribing to the events for every textboxes and in every individual XAML file for this purpose can be time consuming.

    The TextBoxHelper class I implemented has these features:

    • Filtering and accepting only numbers in Double, Int, Uint and Natural format
    • Filtering and accepting only Even or Odd numbers
    • Handling paste event handler to prevent pasting invalid text into our numeric textboxes
    • Can set a Default Value which will be used to prevent invalid data as the last shot by subscribing to the textboxes TextChanged event

    Here is the implementation of TextBoxHelper class:

    public static class TextBoxHelper
    {
        #region Enum Declarations
    
        public enum NumericFormat
        {
            Double,
            Int,
            Uint,
            Natural
        }
    
        public enum EvenOddConstraint
        {
            All,
            OnlyEven,
            OnlyOdd
        }
    
        #endregion
    
        #region Dependency Properties & CLR Wrappers
    
        public static readonly DependencyProperty OnlyNumericProperty =
            DependencyProperty.RegisterAttached("OnlyNumeric", typeof(NumericFormat?), typeof(TextBoxHelper),
                new PropertyMetadata(null, DependencyPropertiesChanged));
        public static void SetOnlyNumeric(TextBox element, NumericFormat value) =>
            element.SetValue(OnlyNumericProperty, value);
        public static NumericFormat GetOnlyNumeric(TextBox element) =>
            (NumericFormat) element.GetValue(OnlyNumericProperty);
    
    
        public static readonly DependencyProperty DefaultValueProperty =
            DependencyProperty.RegisterAttached("DefaultValue", typeof(string), typeof(TextBoxHelper),
                new PropertyMetadata(null, DependencyPropertiesChanged));
        public static void SetDefaultValue(TextBox element, string value) =>
            element.SetValue(DefaultValueProperty, value);
        public static string GetDefaultValue(TextBox element) => (string) element.GetValue(DefaultValueProperty);
    
    
        public static readonly DependencyProperty EvenOddConstraintProperty =
            DependencyProperty.RegisterAttached("EvenOddConstraint", typeof(EvenOddConstraint), typeof(TextBoxHelper),
                new PropertyMetadata(EvenOddConstraint.All, DependencyPropertiesChanged));
        public static void SetEvenOddConstraint(TextBox element, EvenOddConstraint value) =>
            element.SetValue(EvenOddConstraintProperty, value);
        public static EvenOddConstraint GetEvenOddConstraint(TextBox element) =>
            (EvenOddConstraint)element.GetValue(EvenOddConstraintProperty);
    
        #endregion
    
        #region Dependency Properties Methods
    
        private static void DependencyPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is TextBox textBox))
                throw new Exception("Attached property must be used with TextBox.");
    
            switch (e.Property.Name)
            {
                case "OnlyNumeric":
                {
                    var castedValue = (NumericFormat?) e.NewValue;
    
                    if (castedValue.HasValue)
                    {
                        textBox.PreviewTextInput += TextBox_PreviewTextInput;
                        DataObject.AddPastingHandler(textBox, TextBox_PasteEventHandler);
                    }
                    else
                    {
                        textBox.PreviewTextInput -= TextBox_PreviewTextInput;
                        DataObject.RemovePastingHandler(textBox, TextBox_PasteEventHandler);
                    }
    
                    break;
                }
    
                case "DefaultValue":
                {
                    var castedValue = (string) e.NewValue;
    
                    if (castedValue != null)
                    {
                        textBox.TextChanged += TextBox_TextChanged;
                    }
                    else
                    {
                        textBox.TextChanged -= TextBox_TextChanged;
                    }
    
                    break;
                }
            }
        }
    
        #endregion
    
        private static void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var textBox = (TextBox)sender;
    
            string newText;
    
            if (textBox.SelectionLength == 0)
            {
                newText = textBox.Text.Insert(textBox.SelectionStart, e.Text);
            }
            else
            {
                var textAfterDelete = textBox.Text.Remove(textBox.SelectionStart, textBox.SelectionLength);
    
                newText = textAfterDelete.Insert(textBox.SelectionStart, e.Text);
            }
    
            var evenOddConstraint = GetEvenOddConstraint(textBox);
    
            switch (GetOnlyNumeric(textBox))
            {
                case NumericFormat.Double:
                {
                    if (double.TryParse(newText, out double number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:
    
                                if (number % 2 != 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;
    
                                break;
    
                            case EvenOddConstraint.OnlyOdd:
    
                                if (number % 2 == 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;
    
                                break;
                        }
                    }
                    else
                        e.Handled = true;
    
                    break;
                }
    
                case NumericFormat.Int:
                {
                    if (int.TryParse(newText, out int number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:
    
                                if (number % 2 != 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;
    
                                break;
    
                            case EvenOddConstraint.OnlyOdd:
    
                                if (number % 2 == 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;
    
                                break;
                        }
                    }
                    else
                        e.Handled = true;
    
                    break;
                }
    
                case NumericFormat.Uint:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:
    
                                if (number % 2 != 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;
    
                                break;
    
                            case EvenOddConstraint.OnlyOdd:
    
                                if (number % 2 == 0)
                                    e.Handled = true;
                                else
                                    e.Handled = false;
    
                                break;
                        }
                    }
                    else
                        e.Handled = true;
    
                    break;
                }
    
                case NumericFormat.Natural:
                {
                    if (uint.TryParse(newText, out uint number))
                    {
                        if (number == 0)
                            e.Handled = true;
                        else
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:
    
                                    if (number % 2 != 0)
                                        e.Handled = true;
                                    else
                                        e.Handled = false;
    
                                    break;
    
                                case EvenOddConstraint.OnlyOdd:
    
                                    if (number % 2 == 0)
                                        e.Handled = true;
                                    else
                                        e.Handled = false;
    
                                    break;
                            }
                        }
                    }
                    else
                        e.Handled = true;
    
                    break;
                }
            }
        }
    
        private static void TextBox_PasteEventHandler(object sender, DataObjectPastingEventArgs e)
        {
            var textBox = (TextBox)sender;
    
            if (e.DataObject.GetDataPresent(typeof(string)))
            {
                var clipboardText = (string) e.DataObject.GetData(typeof(string));
    
                var newText = textBox.Text.Insert(textBox.SelectionStart, clipboardText);
    
                var evenOddConstraint = GetEvenOddConstraint(textBox);
    
                switch (GetOnlyNumeric(textBox))
                {
                    case NumericFormat.Double:
                    {
                        if (double.TryParse(newText, out double number))
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:
    
                                    if (number % 2 != 0)
                                        e.CancelCommand();
    
                                    break;
    
                                case EvenOddConstraint.OnlyOdd:
    
                                    if (number % 2 == 0)
                                        e.CancelCommand();
    
                                    break;
                            }
                        }
                        else
                            e.CancelCommand();
    
                        break;
                    }
    
                    case NumericFormat.Int:
                    {
                        if (int.TryParse(newText, out int number))
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:
    
                                    if (number % 2 != 0)
                                        e.CancelCommand();
    
                                    break;
    
                                case EvenOddConstraint.OnlyOdd:
    
                                    if (number % 2 == 0)
                                        e.CancelCommand();
    
    
                                    break;
                            }
                        }
                        else
                            e.CancelCommand();
    
                        break;
                    }
    
                    case NumericFormat.Uint:
                    {
                        if (uint.TryParse(newText, out uint number))
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:
    
                                    if (number % 2 != 0)
                                        e.CancelCommand();
    
                                    break;
    
                                case EvenOddConstraint.OnlyOdd:
    
                                    if (number % 2 == 0)
                                        e.CancelCommand();
    
    
                                    break;
                            }
                        }
                        else
                            e.CancelCommand();
    
                        break;
                    }
    
                    case NumericFormat.Natural:
                    {
                        if (uint.TryParse(newText, out uint number))
                        {
                            if (number == 0)
                                e.CancelCommand();
                            else
                            {
                                switch (evenOddConstraint)
                                {
                                    case EvenOddConstraint.OnlyEven:
    
                                        if (number % 2 != 0)
                                            e.CancelCommand();
    
                                        break;
    
                                    case EvenOddConstraint.OnlyOdd:
    
                                        if (number % 2 == 0)
                                            e.CancelCommand();
    
                                        break;
                                }
                            }
                        }
                        else
                        {
                            e.CancelCommand();
                        }
    
                        break;
                    }
                }
            }
            else
            {
                e.CancelCommand();
            }
        }
    
        private static void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            var textBox = (TextBox)sender;
    
            var defaultValue = GetDefaultValue(textBox);
    
            var evenOddConstraint = GetEvenOddConstraint(textBox);
    
            switch (GetOnlyNumeric(textBox))
            {
                case NumericFormat.Double:
                {
                    if (double.TryParse(textBox.Text, out double number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:
    
                                if (number % 2 != 0)
                                    textBox.Text = defaultValue;
    
                                break;
    
                            case EvenOddConstraint.OnlyOdd:
    
                                if (number % 2 == 0)
                                    textBox.Text = defaultValue;
    
                                break;
                        }
                    }
                    else
                        textBox.Text = defaultValue;
    
                    break;
                }
    
                case NumericFormat.Int:
                {
                    if (int.TryParse(textBox.Text, out int number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:
    
                                if (number % 2 != 0)
                                    textBox.Text = defaultValue;
    
                                break;
    
                            case EvenOddConstraint.OnlyOdd:
    
                                if (number % 2 == 0)
                                    textBox.Text = defaultValue;
    
                                break;
                        }
                    }
                    else
                        textBox.Text = defaultValue;
    
                    break;
                }
    
                case NumericFormat.Uint:
                {
                    if (uint.TryParse(textBox.Text, out uint number))
                    {
                        switch (evenOddConstraint)
                        {
                            case EvenOddConstraint.OnlyEven:
    
                                if (number % 2 != 0)
                                    textBox.Text = defaultValue;
    
                                break;
    
                            case EvenOddConstraint.OnlyOdd:
    
                                if (number % 2 == 0)
                                    textBox.Text = defaultValue;
    
                                break;
                        }
                    }
                    else
                        textBox.Text = defaultValue;
    
                    break;
                }
    
                case NumericFormat.Natural:
                {
                    if (uint.TryParse(textBox.Text, out uint number))
                    {
                        if(number == 0)
                            textBox.Text = defaultValue;
                        else
                        {
                            switch (evenOddConstraint)
                            {
                                case EvenOddConstraint.OnlyEven:
    
                                    if (number % 2 != 0)
                                        textBox.Text = defaultValue;
    
                                    break;
    
                                case EvenOddConstraint.OnlyOdd:
    
                                    if (number % 2 == 0)
                                        textBox.Text = defaultValue;
    
                                    break;
                            }
                        }
                    }
                    else
                    {
                        textBox.Text = defaultValue;
                    }
    
                    break;
                }
            }
        }
    }
    

    And here is some example of its easy usage:

    
    

    Or

    
    

    Note that my TextBoxHelper resides in the viewHelpers xmlns alias.

    I hope that this implementation eases some other one's work :)

提交回复
热议问题