How do I make a textbox that only accepts numbers?

后端 未结 30 1625
梦如初夏
梦如初夏 2020-11-21 06:05

I have a windows forms app with a textbox control that I want to only accept integer values. In the past I\'ve done this kind of validation by overloading the KeyPress event

相关标签:
30条回答
  • 2020-11-21 06:49

    Here is a simple standalone Winforms custom control, derived from the standard TextBox, that allows only System.Int32 input (it could be easily adapted for other types such as System.Int64, etc.). It supports copy/paste operations and negative numbers:

    public class Int32TextBox : TextBox
    {
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);
    
            NumberFormatInfo fi = CultureInfo.CurrentCulture.NumberFormat;
    
            string c = e.KeyChar.ToString();
            if (char.IsDigit(c, 0))
                return;
    
            if ((SelectionStart == 0) && (c.Equals(fi.NegativeSign)))
                return;
    
            // copy/paste
            if ((((int)e.KeyChar == 22) || ((int)e.KeyChar == 3))
                && ((ModifierKeys & Keys.Control) == Keys.Control))
                return;
    
            if (e.KeyChar == '\b')
                return;
    
            e.Handled = true;
        }
    
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_PASTE = 0x0302;
            if (m.Msg == WM_PASTE)
            {
                string text = Clipboard.GetText();
                if (string.IsNullOrEmpty(text))
                    return;
    
                if ((text.IndexOf('+') >= 0) && (SelectionStart != 0))
                    return;
    
                int i;
                if (!int.TryParse(text, out i)) // change this for other integer types
                    return;
    
                if ((i < 0) && (SelectionStart != 0))
                    return;
            }
            base.WndProc(ref m);
        }
    

    Update 2017: My first answer has some issues:

    • you can type something that's longer than an integer of a given type (for example 2147483648 is greater than Int32.MaxValue);
    • more generally, there's no real validation of the result of what has been typed;
    • it only handles int32, you'll have to write specific TextBox derivated control for each type (Int64, etc.)

    So I came up with another version that's more generic, that still supports copy/paste, + and - sign, etc.

    public class ValidatingTextBox : TextBox
    {
        private string _validText;
        private int _selectionStart;
        private int _selectionEnd;
        private bool _dontProcessMessages;
    
        public event EventHandler<TextValidatingEventArgs> TextValidating;
    
        protected virtual void OnTextValidating(object sender, TextValidatingEventArgs e) => TextValidating?.Invoke(sender, e);
    
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (_dontProcessMessages)
                return;
    
            const int WM_KEYDOWN = 0x100;
            const int WM_ENTERIDLE = 0x121;
            const int VK_DELETE = 0x2e;
    
            bool delete = m.Msg == WM_KEYDOWN && (int)m.WParam == VK_DELETE;
            if ((m.Msg == WM_KEYDOWN && !delete) || m.Msg == WM_ENTERIDLE)
            {
                DontProcessMessage(() =>
                {
                    _validText = Text;
                    _selectionStart = SelectionStart;
                    _selectionEnd = SelectionLength;
                });
            }
    
            const int WM_CHAR = 0x102;
            const int WM_PASTE = 0x302;
            if (m.Msg == WM_CHAR || m.Msg == WM_PASTE || delete)
            {
                string newText = null;
                DontProcessMessage(() =>
                {
                    newText = Text;
                });
    
                var e = new TextValidatingEventArgs(newText);
                OnTextValidating(this, e);
                if (e.Cancel)
                {
                    DontProcessMessage(() =>
                    {
                        Text = _validText;
                        SelectionStart = _selectionStart;
                        SelectionLength = _selectionEnd;
                    });
                }
            }
        }
    
        private void DontProcessMessage(Action action)
        {
            _dontProcessMessages = true;
            try
            {
                action();
            }
            finally
            {
                _dontProcessMessages = false;
            }
        }
    }
    
    public class TextValidatingEventArgs : CancelEventArgs
    {
        public TextValidatingEventArgs(string newText) => NewText = newText;
        public string NewText { get; }
    }
    

    For Int32, you can either derive from it, like this:

    public class Int32TextBox : ValidatingTextBox
    {
        protected override void OnTextValidating(object sender, TextValidatingEventArgs e)
        {
            e.Cancel = !int.TryParse(e.NewText, out int i);
        }
    }
    

    or w/o derivation, use the new TextValidating event like this:

    var vtb = new ValidatingTextBox();
    ...
    vtb.TextValidating += (sender, e) => e.Cancel = !int.TryParse(e.NewText, out int i);
    

    but what's nice is it works with any string, and any validation routine.

    0 讨论(0)
  • 2020-11-21 06:49

    I have made something for this on CodePlex.

    It works by intercepting the TextChanged event. If the result is a good number it will be stored. If it is something wrong, the last good value will be restored. The source is a bit too large to publish here, but here is a link to the class that handles the core of this logic.

    0 讨论(0)
  • 2020-11-21 06:49
    private void txt3_KeyPress(object sender, KeyPressEventArgs e)
    {
        for (int h = 58; h <= 127; h++)
        {
            if (e.KeyChar == h)             //58 to 127 is alphabets tat will be         blocked
            {
                e.Handled = true;
            }
        }
        for(int k=32;k<=47;k++)
        {
            if (e.KeyChar == k)              //32 to 47 are special characters tat will 
            {                                  be blocked
                e.Handled = true;
            }
        }
    }
    

    try this is very simple

    0 讨论(0)
  • 2020-11-21 06:49

    Do not forget that a user can paste an invalid text in a TextBox.

    If you want to restrict that, follow the below code:

    private void ultraTextEditor1_TextChanged(object sender, EventArgs e)
    {
        string append="";
        foreach (char c in ultraTextEditor1.Text)
        {
            if ((!Char.IsNumber(c)) && (c != Convert.ToChar(Keys.Back)))
            {
    
            }
            else
            {
                append += c;
            }
        }
    
        ultraTextEditor1.Text = append;
    }   
    
    0 讨论(0)
  • 2020-11-21 06:50

    Hi you can do something like this in the textchanged event of the textbox.

    here is a demo

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            string actualdata = string.Empty;
            char[] entereddata = textBox1.Text.ToCharArray();
            foreach (char aChar in entereddata.AsEnumerable())
            {
                if (Char.IsDigit(aChar))
                {
                    actualdata = actualdata + aChar;
                    // MessageBox.Show(aChar.ToString());
                }
                else
                {
                    MessageBox.Show(aChar + " is not numeric");
                    actualdata.Replace(aChar, ' ');
                    actualdata.Trim();
                }
            }
            textBox1.Text = actualdata;
        }
    
    0 讨论(0)
  • 2020-11-21 06:51

    Take a look at Input handling in WinForm

    I have posted my solution which uses the ProcessCmdKey and OnKeyPress events on the textbox. The comments show you how to use a Regex to verify the keypress and block/allow appropriately.

    0 讨论(0)
提交回复
热议问题