我有一个windows窗体应用程序与一个文本框控件,我想只接受整数值。在过去,我通过重载KeyPress事件并删除不符合规范的字符来进行这种验证。我已经看了MaskedTextBox控件,但我想一个更通用的解决方案,可以与也许正则表达式,或依赖于其他控件的值。

理想情况下,按下非数字字符要么不产生结果,要么立即向用户提供关于无效字符的反馈。


当前回答

我已经为各种验证创建了一个可重用的文本框扩展类,并考虑共享它。

您所需要做的就是引发一个TextChange事件,然后调用Validate方法。它是这样的:

private void tbxAmount_TextChanged(object sender, EventArgs e)
{ 
    tbxAmount.Validate(TextValidator.ValidationType.Amount);
}

下面是扩展类:

public static class TextValidator
{
    public enum ValidationType
    {
        Amount,
        Integer
    }

    /// <summary>
    /// Validate a textbox on text change.
    /// </summary>
    /// <param name="tbx"></param>
    /// <param name="validationType"></param>
    public static void Validate(this TextBox tbx, ValidationType validationType)
    {
        PerformValidation(tbx, validationType);
        tbx.Select(tbx.Text.Length, 0);
    }


    private static void PerformValidation(this TextBox tbx, ValidationType validationType)
    {
        char[] enteredString = tbx.Text.ToCharArray();
        switch (validationType)
        {
            case ValidationType.Amount:
                tbx.Text = AmountValidation(enteredString);
                break;

            case ValidationType.Integer:
                tbx.Text = IntegerValidation(enteredString);
                break;

            default:
                break;
        }

        tbx.SelectionStart = tbx.Text.Length;
    }



    private static string AmountValidation(char[] enteredString)
    {
        string actualString = string.Empty;
        int count = 0;
        foreach (char c in enteredString.AsEnumerable())
        {
            if (count >= 1 && c == '.')
            { actualString.Replace(c, ' '); actualString.Trim(); }
            else
            {
                if (Char.IsDigit(c))
                {
                    actualString = actualString + c;
                }

                if (c == '.')
                {
                    actualString = actualString + c; count++;
                }

                else
                {
                    actualString.Replace(c, ' ');
                    actualString.Trim();
                }
            }
        }
        return actualString;
    }


    private static string IntegerValidation(char[] enteredString)
    {
        string actualString = string.Empty;
        foreach (char c in enteredString.AsEnumerable())
        {
            if (Char.IsDigit(c))
            {
                actualString = actualString + c;
            }
            else
            {
                actualString.Replace(c, ' ');
                actualString.Trim();
            }
        }
        return actualString;
    }
}

你可以在这里找到完整的代码

其他回答

很抱歉吵醒死人,但我想有人可能会觉得这对将来的参考有用。

以下是我的处理方法。它处理浮点数,但可以很容易地修改为整数。

基本上你只能按0 - 9和。

前面只能有一个0。

所有其他字符将被忽略,光标位置保持不变。

    private bool _myTextBoxChanging = false;

    private void myTextBox_TextChanged(object sender, EventArgs e)
    {
        validateText(myTextBox);
    }

    private void validateText(TextBox box)
    {
        // stop multiple changes;
        if (_myTextBoxChanging)
            return;
        _myTextBoxChanging = true;

        string text = box.Text;
        if (text == "")
            return;
        string validText = "";
        bool hasPeriod = false;
        int pos = box.SelectionStart;
        for (int i = 0; i < text.Length; i++ )
        {
            bool badChar = false;
            char s = text[i];
            if (s == '.')
            {
                if (hasPeriod)
                    badChar = true;
                else
                    hasPeriod = true;
            }
            else if (s < '0' || s > '9')
                badChar = true;

            if (!badChar)
                validText += s;
            else
            {
                if (i <= pos)
                    pos--;
            }
        }

        // trim starting 00s
        while (validText.Length >= 2 && validText[0] == '0')
        {
            if (validText[1] != '.')
            {
                validText = validText.Substring(1);
                if (pos < 2)
                    pos--;
            }
            else
                break;
        }

        if (pos > validText.Length)
            pos = validText.Length;
        box.Text = validText;
        box.SelectionStart = pos;
        _myTextBoxChanging = false;
    }

下面是一个快速修改的int版本:

    private void validateText(TextBox box)
    {
        // stop multiple changes;
        if (_myTextBoxChanging)
            return;
        _myTextBoxChanging = true;

        string text = box.Text;
        if (text == "")
            return;
        string validText = "";
        int pos = box.SelectionStart;
        for (int i = 0; i < text.Length; i++ )
        {
            char s = text[i];
            if (s < '0' || s > '9')
            {
                if (i <= pos)
                    pos--;
            }
            else
                validText += s;
        }

        // trim starting 00s 
        while (validText.Length >= 2 && validText.StartsWith("00")) 
        { 
            validText = validText.Substring(1); 
            if (pos < 2) 
                pos--; 
        } 

        if (pos > validText.Length)
            pos = validText.Length;
        box.Text = validText;
        box.SelectionStart = pos;
        _myTextBoxChanging = false;
    }

只需使用NumericUpDown控件,并设置那些丑陋的上下按钮可见性为假。

numericUpDown1.Controls[0].Visible = false;

NumericUpDown实际上是一个包含“旋转框”(上下按钮)的控件集合,一个文本框和一些代码来验证和wange-jangle。

标记:

YourNumericUpDown.Controls[0].visible = false 

将隐藏按钮,同时保持底层代码活动。

虽然不是一个明显的解决方案,但它简单而有效。. controls[1]将隐藏文本框部分,如果你想这样做的话。

整数和浮点数都需要被接受,包括负数。

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    // Text
    string text = ((Control) sender).Text;

    // Is Negative Number?
    if (e.KeyChar == '-' && text.Length == 0)
    {
        e.Handled = false;
        return;
    }

    // Is Float Number?
    if (e.KeyChar == '.' && text.Length > 0 && !text.Contains("."))
    {
        e.Handled = false;
        return;
    }

    // Is Digit?
    e.Handled = (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar));
}

你可以使用TextChanged/ Keypress事件,使用正则表达式过滤数字,并采取一些行动。

这是一个简单的独立的Winforms自定义控件,从标准的TextBox派生而来,只允许System。Int32输入(它可以很容易地适用于其他类型,如System。Int64,等等)。它支持复制/粘贴操作和负数:

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);
    }

2017年更新:我的第一个答案有一些问题:

你可以输入一个比给定类型的整数更长的值(例如2147483648大于Int32.MaxValue); 更一般地说,对于输入的结果没有真正的验证; 它只处理int32,你必须写特定的TextBox衍生控件为每种类型(Int64等)

所以我提出了另一个更通用的版本,它仍然支持复制/粘贴,+和-号等。

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; }
}

对于Int32,你可以从它导出,像这样:

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

或w/o派生,使用新的textvalididating事件,像这样:

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

但它的优点是它适用于任何字符串和任何验证例程。