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

后端 未结 30 2359
悲哀的现实
悲哀的现实 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:19

    Here is my version of it. It's based on a base ValidatingTextBox class that just undoes what has been done if it's not "valid". It supports paste, cut, delete, backspace, +, - etc.

    For 32-bit integer, there is a Int32TextBox class that just compares with an int. I have also added floating point validation classes.

    public class ValidatingTextBox : TextBox
    {
        private bool _inEvents;
        private string _textBefore;
        private int _selectionStart;
        private int _selectionLength;
    
        public event EventHandler ValidateText;
    
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            if (_inEvents)
                return;
    
            _selectionStart = SelectionStart;
            _selectionLength = SelectionLength;
            _textBefore = Text;
        }
    
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            if (_inEvents)
                return;
    
            _inEvents = true;
            var ev = new ValidateTextEventArgs(Text);
            OnValidateText(this, ev);
            if (ev.Cancel)
            {
                Text = _textBefore;
                SelectionStart = _selectionStart;
                SelectionLength = _selectionLength;
            }
            _inEvents = false;
        }
    
        protected virtual void OnValidateText(object sender, ValidateTextEventArgs e) => ValidateText?.Invoke(this, e);
    }
    
    public class ValidateTextEventArgs : CancelEventArgs
    {
        public ValidateTextEventArgs(string text) => Text = text;
    
        public string Text { get; }
    }
    
    public class Int32TextBox : ValidatingTextBox
    {
        protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !int.TryParse(e.Text, out var value);
    }
    
    public class Int64TextBox : ValidatingTextBox
    {
        protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !long.TryParse(e.Text, out var value);
    }
    
    public class DoubleTextBox : ValidatingTextBox
    {
        protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !double.TryParse(e.Text, out var value);
    }
    
    public class SingleTextBox : ValidatingTextBox
    {
        protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !float.TryParse(e.Text, out var value);
    }
    
    public class DecimalTextBox : ValidatingTextBox
    {
        protected override void OnValidateText(object sender, ValidateTextEventArgs e) => e.Cancel = !decimal.TryParse(e.Text, out var value);
    }
    

    Note 1: When using WPF binding, you must make sure you use the class that fits the bound property type otherwise, it may lead to strange results.

    Note 2: When using floating point classes with WPF binding, make sure the binding uses the current culture to match the TryParse method I've used.

提交回复
热议问题