ChatGPT解决这个技术问题 Extra ChatGPT

如何制作一个只接受数字的文本框?

我有一个带有文本框控件的 Windows 窗体应用程序,我只想接受整数值。在过去,我通过重载 KeyPress 事件并仅删除不符合规范的字符来完成这种验证。我查看了 MaskedTextBox 控件,但我想要一个更通用的解决方案,它可以使用正则表达式,或者取决于其他控件的值。

理想情况下,这会表现为按下非数字字符将不会产生任何结果或立即向用户提供有关无效字符的反馈。

数字还是数字?很大的不同:即使是整数也可以是负数
这个问题是针对数字的,包括整个有理数集。

B
Bitterblue

两种选择:

请改用 NumericUpDown。 NumericUpDown 为您进行过滤,这很好。当然,它还使您的用户能够点击键盘上的向上和向下箭头来增加和减少当前值。处理适当的键盘事件以防止除数字输入之外的任何内容。我在标准 TextBox 上使用这两个事件处理程序取得了成功: private void textBox1_KeyPress(object sender, KeyPressEventArgs e) { if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e .KeyChar != '.')) { e.Handled = true; } // 只允许一位小数 if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1)) { e.Handled = true; } }

如果您的 TextBox 不允许使用小数位,您可以删除对 '.' 的检查(以及对多个 '.' 的后续检查)。如果您的 TextBox 应该允许负值,您还可以添加对 '-' 的检查。

如果要限制用户的位数,请使用:textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits


NumericUpDown 的唯一缺点是,当您输入超出允许的最大值或最小值的值时,它不会提供任何反馈 - 它只会更改您输入的内容。 TextBox 至少可以允许无效值,因此您可以在用户提交表单时警告用户。
这是真的——用户总是可以粘贴一些非数字字符。你会希望表单验证能够捕捉到这一点,因为在某些时候你会想要做一个 Int32.TryParse 或其他东西。
您需要一些额外的努力来通过替换“。”的检查来使其全球化。检查 CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator。
@HamishGrubijan,IsControl 与 Control 键无关;它返回一个字符是否是一个控制字符。通过允许控制字符,您不会破坏退格、删除或箭头键等内容
顺便说一句,这仍然接受非法的 ctrl+v 输入;一个甚至存在于官方 NumericUpDown 控件中的错误。
B
BFree

仅仅因为在一行中做事总是更有趣……

 private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
    }

注意:这不会阻止用户复制/粘贴到此文本框中。这不是清理数据的万无一失的方法。


这不是通用解决方案,因为它仅适用于整数。我最近不得不实现这样的事情,我最终尝试将结果字符串解析为数字并仅在解析成功时才允许输入
当多个方法处理来自同一文本框的 KeyPress 事件时,这可能不起作用。一个事件可能会将 e.Handled 设置为 true,然后另一个事件会将其设置回 false。一般来说,最好使用 if (...) e.Handled = true;
您可以禁用 ShortcutsEnabled 属性以防止通过键盘或菜单进行复制粘贴
哈哈!是的!一个衬垫!
嗯。使用正则表达式覆盖它的 TextChanged 事件可以修复复制粘贴;)
A
Adrian Mole

我从上下文和您使用的标签假设您正在编写一个 .NET C# 应用程序。在这种情况下,您可以订阅文本更改事件,并验证每个击键。

private void textBox1_TextChanged(object sender, EventArgs e)
{
    if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
    {
        MessageBox.Show("Please enter only numbers.");
        textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
    }
}

如果您在数字中间输入,那会不会产生非常奇怪的效果?
它也应该是:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
如果第一个字符本身不是数字怎么办......在这种情况下不会减去 1 会引发错误......
此外,使用 TextChanged 而不是 KeyPress 会产生一些递归,因为代码将在 Remove 方法之后跳转到第二个 TextChanged 事件。
您为 IsMatch 函数切换了输入和模式参数。输入应该是第一,然后是模式。 msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx
S
Simon Mourier

这是一个简单的独立 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,您必须为每种类型(Int64 等)编写特定的 TextBox 派生控件

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

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

或没有派生,使用新的 TextValidating 事件,如下所示:

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

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


这很棒,漂亮且简单,易于使用,并且可以处理不寻常的输入尝试。谢谢!
请注意 2017 版本,当有一个值(例如 1)并且您按退格键时,它会被忽略,而如果您说 120 并按三次退格键,我们会留下 1。
您的 ValidatingTextbox 是迄今为止我见过的最好的实现。简单有效。谢谢!
如何在我的项目 2019 中实施它?
你可以让多行文本框为真吗?我想在多行上允许正双打
T
TomXP411

这正是 Validated/Validating 事件的设计目的。

这是有关该主题的 MSDN 文章:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

TL;DR 版本:检查 Validating 事件中的 .Text 属性,并在数据无效时设置 e.Cancel=True

当您设置 e.Cancel=True 时,用户不能离开该字段,但您需要向他们提供某种反馈,表明有问题。我将框的背景颜色更改为浅红色以表示存在问题。确保在以良好值调用 Validating 时将其设置回 SystemColors.Window


+1 提到了一种非常 API 惯用的方法。我对 Windows 窗体相对较新,它是一个功能丰富的丛林。 MSDN 文档,因此还要感谢指向 Validating 的特定文档指针。 <nitpick>OP 提到立即禁止/指示无效字符是理想的,但 Validating 似乎需要在其生效之前将焦点移至另一个表单/控件。</nitpick> 不过,这是一个很好的方法,并且总是在更一般的情况下值得考虑。
这是一个很好的解决方案,因为需要最少的实现。值得注意的是,Validating 事件仅在控件失去焦点时发生。但是,很容易从按键调用相同的验证函数来进行实时验证。
A
Andrew Kennan

试试 MaskedTextBox。它采用简单的掩码格式,因此您可以将输入限制为数字或日期等。


我特别不想使用 MaskedTextBox。他们允许的格式可能非常有限。他们适用于这种情况,但我想做一些更一般的事情。
d
default

您可以使用 TextChanged 事件

private void textBox_BiggerThan_TextChanged(object sender, EventArgs e)
{
    long a;
    if (! long.TryParse(textBox_BiggerThan.Text, out a))
    {
        // If not int clear textbox text or Undo() last operation
        textBox_LessThan.Clear();
    }
}

如果您使用 Undo(),它看起来应该可以正常工作,但它会导致 StackOverflowException
看起来 TextChanged 属性是您想要撤消()的例程的一部分。我有整个窗口的变量,我正在使用 public int txtBoxValue,如果 tryParse 不起作用,我会通过 txtBox.Text = txtBoxValue.ToString(); 恢复 txtBox 中的文本
R
Roger Garrett

这可能很有用。它允许“真实”数值,包括正确的小数点和前面的加号或减号。从相关的 KeyPress 事件中调用它。

       private bool IsOKForDecimalTextBox(char theCharacter, TextBox theTextBox)
    {
        // Only allow control characters, digits, plus and minus signs.
        // Only allow ONE plus sign.
        // Only allow ONE minus sign.
        // Only allow the plus or minus sign as the FIRST character.
        // Only allow ONE decimal point.
        // Do NOT allow decimal point or digits BEFORE any plus or minus sign.

        if (
            !char.IsControl(theCharacter)
            && !char.IsDigit(theCharacter)
            && (theCharacter != '.')
            && (theCharacter != '-')
            && (theCharacter != '+')
        )
        {
            // Then it is NOT a character we want allowed in the text box.
            return false;
        }



        // Only allow one decimal point.
        if (theCharacter == '.'
            && theTextBox.Text.IndexOf('.') > -1)
        {
            // Then there is already a decimal point in the text box.
            return false;
        }

        // Only allow one minus sign.
        if (theCharacter == '-'
            && theTextBox.Text.IndexOf('-') > -1)
        {
            // Then there is already a minus sign in the text box.
            return false;
        }

        // Only allow one plus sign.
        if (theCharacter == '+'
            && theTextBox.Text.IndexOf('+') > -1)
        {
            // Then there is already a plus sign in the text box.
            return false;
        }

        // Only allow one plus sign OR minus sign, but not both.
        if (
            (
                (theCharacter == '-')
                || (theCharacter == '+')
            )
            && 
            (
                (theTextBox.Text.IndexOf('-') > -1)
                ||
                (theTextBox.Text.IndexOf('+') > -1)
            )
            )
        {
            // Then the user is trying to enter a plus or minus sign and
            // there is ALREADY a plus or minus sign in the text box.
            return false;
        }

        // Only allow a minus or plus sign at the first character position.
        if (
            (
                (theCharacter == '-')
                || (theCharacter == '+')
            )
            && theTextBox.SelectionStart != 0
            )
        {
            // Then the user is trying to enter a minus or plus sign at some position 
            // OTHER than the first character position in the text box.
            return false;
        }

        // Only allow digits and decimal point AFTER any existing plus or minus sign
        if  (
                (
                    // Is digit or decimal point
                    char.IsDigit(theCharacter)
                    ||
                    (theCharacter == '.')
                )
                &&
                (
                    // A plus or minus sign EXISTS
                    (theTextBox.Text.IndexOf('-') > -1)
                    ||
                    (theTextBox.Text.IndexOf('+') > -1)
                )
                &&
                    // Attempting to put the character at the beginning of the field.
                    theTextBox.SelectionStart == 0
            )
        {
            // Then the user is trying to enter a digit or decimal point in front of a minus or plus sign.
            return false;
        }

        // Otherwise the character is perfectly fine for a decimal value and the character
        // may indeed be placed at the current insertion position.
        return true;
    }

D
Dean Seo

只需使用 NumericUpDown 控件并将那些难看的向上向下按钮的可见性设置为 false

numericUpDown1.Controls[0].Visible = false;

NumericUpDown 实际上是一个控件集合,其中包含一个“旋转框”(向上向下按钮)、一个文本框和一些用于验证和将它们组合在一起的代码。

标记:

YourNumericUpDown.Controls[0].visible = false 

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

虽然不是一个明显的解决方案,但它既简单又有效。如果您想这样做,.Controls[1] 会隐藏文本框部分。


接受的答案不包括有关如何删除向上向下按钮的任何信息,如何这样做并不明显,因为没有人类可读的界面来启用或禁用它们。 NumericUpDown 实际上是包含一个文本框和一个“旋转框”(向上向下按钮)和一些处理输入验证的代码的控件的集合。
F
Fabio Iotti

我一直在研究一组组件来完成 WinForms 中缺少的东西,这里是:Advanced Forms

特别是这是 Regex TextBox 的类

/// <summary>Represents a Windows text box control that only allows input that matches a regular expression.</summary>
public class RegexTextBox : TextBox
{
    [NonSerialized]
    string lastText;

    /// <summary>A regular expression governing the input allowed in this text field.</summary>
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public virtual Regex Regex { get; set; }

    /// <summary>A regular expression governing the input allowed in this text field.</summary>
    [DefaultValue(null)]
    [Category("Behavior")]
    [Description("Sets the regular expression governing the input allowed for this control.")]
    public virtual string RegexString {
        get {
            return Regex == null ? string.Empty : Regex.ToString();
        }
        set {
            if (string.IsNullOrEmpty(value))
                Regex = null;
            else
                Regex = new Regex(value);
        }
    }

    protected override void OnTextChanged(EventArgs e) {
        if (Regex != null && !Regex.IsMatch(Text)) {
            int pos = SelectionStart - Text.Length + (lastText ?? string.Empty).Length;
            Text = lastText;
            SelectionStart = Math.Max(0, pos);
        }

        lastText = Text;

        base.OnTextChanged(e);
    }
}

只需添加类似 myNumbericTextBox.RegexString = "^(\\d+|)$"; 的内容就足够了。


J
John Saunders

只需在文本框中使用此代码:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

    if (!double.TryParse(textBox1.Text, out parsedValue))
    {
        textBox1.Text = "";
    }
}

G
GvS

我在 CodePlex 上为此做了一些事情。

它通过拦截 TextChanged 事件来工作。如果结果是一个好的数字,它将被存储。如果出现问题,将恢复最后的良好值。源代码有点太大,无法在此处发布,但 here is a link to the class 处理了此逻辑的核心。


P
Paul Roub

在我们定义了文本框的网页中,我们可以添加一个 onkeypress 事件来仅接受数字。它不会显示任何消息,但会防止您输入错误。它对我有用,用户只能输入数字。

<asp:TextBox runat="server" ID="txtFrom"
     onkeypress="if(isNaN(String.fromCharCode(event.keyCode))) return false;">

p
plamut

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

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

I
Ing. Gerardo Sánchez

这是我的方法:

使用 linq(易于修改过滤器)复制/粘贴证明代码在您按下禁止字符时保持插入位置接受左零和任何大小的数字 private void numeroCuenta_TextChanged(object sender, EventArgs e) { string org = numeroCuenta.Text;格式化字符串 = string.Concat(org.Where(c => (c >= '0' && c <= '9')));如果(格式化!= org){ int s = numeroCuenta.SelectionStart; if (s > 0 && formated.Length > s && org[s - 1] != formated[s - 1]) s--; numeroCuenta.Text = 格式化; numeroCuenta.SelectionStart = s; } }


K
Kye

这是使用 .NET 5/Core 实现此目的的一种简便快捷的方法

private void textBox1_KeyDown(object sender, KeyEventArgs e) {
  if (e.KeyData != Keys.Back)
    e.SuppressKeyPress = !int.TryParse(Convert.ToString((char) e.KeyData), out int _);
}

编辑:添加了对退格键的支持


我正在寻找一种在多行文本框中允许正整数/双精度数的方法。你的方法能做到吗?
P
Perpetualcoder

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


S
Shaz

我会在 KeyDown 事件中处理它。

void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            char c = Convert.ToChar(e.PlatformKeyCode);
            if (!char.IsDigit(c))
            {
                e.Handled = true;
            }
        }

像“Backspace”、“Delete”、“Arrow-Key-Left”、“Arrow-Key-Right”、复制和粘贴、由 Numpad 输入的数字之类的键呢(它们被交易为 !digit)
只需添加一些类似这样的测试: if (!char.IsDigit(c) && c != (char)Keys.Back)
N
Natan Streppel
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;
        }
    }
}

试试这个很简单


C
Community

看看Input handling in WinForm

我已经发布了我的解决方案,它在文本框中使用 ProcessCmdKey 和 OnKeyPress 事件。评论向您展示了如何使用正则表达式来验证按键并适当地阻止/允许。


C
Chandan Kumar

嗨,您可以在文本框的 textchanged 事件中执行类似的操作。

这是一个演示

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

谢谢,它非常有用。
W
William

似乎这个问题的许多当前答案都是手动解析输入文本。如果您正在寻找特定的内置数字类型(例如 intdouble),为什么不将工作委托给该类型的 TryParse 方法呢?例如:

public class IntTextBox : TextBox
{
    string PreviousText = "";
    int BackingResult;

    public IntTextBox()
    {
        TextChanged += IntTextBox_TextChanged;
    }

    public bool HasResult { get; private set; }

    public int Result
    {
        get
        {
            return HasResult ? BackingResult : default(int);
        }
    }

    void IntTextBox_TextChanged(object sender, EventArgs e)
    {
        HasResult = int.TryParse(Text, out BackingResult);

        if (HasResult || string.IsNullOrEmpty(Text))
        {
            // Commit
            PreviousText = Text;
        }
        else
        {
            // Revert
            var changeOffset = Text.Length - PreviousText.Length;
            var previousSelectionStart =
                Math.Max(0, SelectionStart - changeOffset);

            Text = PreviousText;
            SelectionStart = previousSelectionStart;
        }
    }
}

如果您想要更通用但仍与 Visual Studio 的设计器兼容的东西:

public class ParsableTextBox : TextBox
{
    TryParser BackingTryParse;
    string PreviousText = "";
    object BackingResult;

    public ParsableTextBox()
        : this(null)
    {
    }

    public ParsableTextBox(TryParser tryParse)
    {
        TryParse = tryParse;

        TextChanged += ParsableTextBox_TextChanged;
    }

    public delegate bool TryParser(string text, out object result);

    public TryParser TryParse
    {
        set
        {
            Enabled = !(ReadOnly = value == null);

            BackingTryParse = value;
        }
    }

    public bool HasResult { get; private set; }

    public object Result
    {
        get
        {
            return GetResult<object>();
        }
    }

    public T GetResult<T>()
    {
        return HasResult ? (T)BackingResult : default(T);
    }

    void ParsableTextBox_TextChanged(object sender, EventArgs e)
    {
        if (BackingTryParse != null)
        {
            HasResult = BackingTryParse(Text, out BackingResult);
        }

        if (HasResult || string.IsNullOrEmpty(Text))
        {
            // Commit
            PreviousText = Text;
        }
        else
        {
            // Revert
            var changeOffset = Text.Length - PreviousText.Length;
            var previousSelectionStart =
                Math.Max(0, SelectionStart - changeOffset);

            Text = PreviousText;
            SelectionStart = previousSelectionStart;
        }
    }
}

最后,如果您想要一些完全通用的东西并且不关心 Designer 支持:

public class ParsableTextBox<T> : TextBox
{
    TryParser BackingTryParse;
    string PreviousText;
    T BackingResult;

    public ParsableTextBox()
        : this(null)
    {
    }

    public ParsableTextBox(TryParser tryParse)
    {
        TryParse = tryParse;

        TextChanged += ParsableTextBox_TextChanged;
    }

    public delegate bool TryParser(string text, out T result);

    public TryParser TryParse
    {
        set
        {
            Enabled = !(ReadOnly = value == null);

            BackingTryParse = value;
        }
    }

    public bool HasResult { get; private set; }

    public T Result
    {
        get
        {
            return HasResult ? BackingResult : default(T);
        }
    }

    void ParsableTextBox_TextChanged(object sender, EventArgs e)
    {
        if (BackingTryParse != null)
        {
            HasResult = BackingTryParse(Text, out BackingResult);
        }

        if (HasResult || string.IsNullOrEmpty(Text))
        {
            // Commit
            PreviousText = Text;
        }
        else
        {
            // Revert
            var changeOffset = Text.Length - PreviousText.Length;
            var previousSelectionStart =
                Math.Max(0, SelectionStart - changeOffset);

            Text = PreviousText;
            SelectionStart = previousSelectionStart;
        }
    }
}

P
PolarBear

使用 Fabio Iotti's answer 中描述的方法,我创建了一个更通用的解决方案:

public abstract class ValidatedTextBox : TextBox {
    private string m_lastText = string.Empty;
    protected abstract bool IsValid(string text);
    protected sealed override void OnTextChanged(EventArgs e) {
        if (!IsValid(Text)) {
            var pos = SelectionStart - Text.Length + m_lastText.Length;
            Text = m_lastText;
            SelectionStart = Math.Max(0, pos);
        }
        m_lastText = Text;
        base.OnTextChanged(e);
    }
}

“ValidatedTextBox”,其中包含所有重要的验证行为。剩下要做的就是从此类继承并使用所需的任何验证逻辑覆盖“IsValid”方法。例如,使用这个类,可以创建“RegexedTextBox”,它只接受匹配特定正则表达式的字符串:

public abstract class RegexedTextBox : ValidatedTextBox {
    private readonly Regex m_regex;
    protected RegexedTextBox(string regExpString) {
        m_regex = new Regex(regExpString);
    }
    protected override bool IsValid(string text) {
        return m_regex.IsMatch(Text);
    }
}

之后,继承“RegexedTextBox”类,我们可以轻松创建“PositiveNumberTextBox”和“PositiveFloatingPointNumberTextBox”控件:

public sealed class PositiveNumberTextBox : RegexedTextBox {
    public PositiveNumberTextBox() : base(@"^\d*$") { }
}

public sealed class PositiveFloatingPointNumberTextBox : RegexedTextBox {
    public PositiveFloatingPointNumberTextBox()
        : base(@"^(\d+\" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + @")?\d*$") { }
}

y
yardape

很抱歉唤醒死者,但我想有人可能会发现这对将来的参考很有用。

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

基本上你只能按 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;
    }

这个解决方案是用警告重新发明轮子。以本地化为例。
如果允许多行,您将如何做到这一点?
u
user1626874

这个适用于复制和粘贴,拖放,按键,防止溢出并且非常简单

public partial class IntegerBox : TextBox 
{
    public IntegerBox()
    {
        InitializeComponent();
        this.Text = 0.ToString();
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
        base.OnPaint(pe);
    }

    private String originalValue = 0.ToString();

    private void Integerbox_KeyPress(object sender, KeyPressEventArgs e)
    {
        originalValue = this.Text;
    }

    private void Integerbox_TextChanged(object sender, EventArgs e)
    {
        try
        {
            if(String.IsNullOrWhiteSpace(this.Text))
            {
                this.Text = 0.ToString();
            }
            this.Text = Convert.ToInt64(this.Text.Trim()).ToString();
        }
        catch (System.OverflowException)
        {
            MessageBox.Show("Value entered is to large max value: " + Int64.MaxValue.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            this.Text = originalValue;
        }
        catch (System.FormatException)
        {                
            this.Text = originalValue;
        }
        catch (System.Exception ex)
        {
            this.Text = originalValue;
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK , MessageBoxIcon.Error);
        }
    }       
}

D
Dean Seo

不要忘记用户可以在 TextBox 中粘贴无效文本。

如果你想限制它,请按照以下代码:

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

D
Dean Seo

我也在寻找仅检查文本框中数字的最佳方法,而按键的问题是它不支持通过右键单击或剪贴板进行复制粘贴,因此提出了此代码,该代码验证光标何时离开文本字段并检查空字段。 (新人改编版)

private void txtFirstValue_MouseLeave(object sender, EventArgs e)
{
    int num;
    bool isNum = int.TryParse(txtFirstValue.Text.Trim(), out num);

    if (!isNum && txtFirstValue.Text != String.Empty)
    {
        MessageBox.Show("The First Value You Entered Is Not a Number, Please Try Again", "Invalid Value Detected", MessageBoxButtons.OK, MessageBoxIcon.Error);
        txtFirstValue.Clear();
    }
}

对于要使用的事件,MouseLeave 似乎是一个非常糟糕的选择。
@LarsTech 我认为是 textchanged 甚至会在用户意识到错误并尝试修复它之前导致错误消息框,所以我认为我会做得更好。你认为这个案子最好的事件是什么?
@AlstonAntony 迟到的评论,我知道。但是一个在右键单击时激活的简单单击事件就足够了,不是吗?
o
osman

这里有30多个答案,很多答案很有帮助。但我想为 System.Windows.Forms.TextBox 和 System.Windows.Controls.TextBox 共享一个通用表单。

System.Windows.Controls.TextBox 中没有可用的 KeyPress 事件。这个答案适用于那些想要为 System.Windows.Forms.TextBox 和 System.Windows.Controls.TextBox 实现相同逻辑的人。

这是 NumberTextBox 代码。使用注释行代替 System.Windows.Controls.TextBox 的前一行。

public class NumberTextBox : System.Windows.Forms.TextBox
//public class NumberTextBox : System.Windows.Controls.TextBox
{
    private double _maxValue;
    private double _minValue;
    private bool _flag;
    private string _previousValue;

    public NumberTextBox()
    {
        this.TextAlign = HorizontalAlignment.Right;
        //TextAlignment = TextAlignment.Right;
        KeyDown += TextBox_KeyDown;
        TextChanged += TextBox_TextChanged;
        _minValue = double.MinValue;
        _maxValue = double.MaxValue;
    }

    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        _previousValue = this.Text;
        _flag = this.SelectedText.Length > 0;
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    //private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var text = this.Text;
        if (text.Length < 1) return;
        var cursorPosition = SelectionStart == 0 ? SelectionStart : SelectionStart - 1;
        var insertedChar = text[cursorPosition];
        if (IsInvalidInput(insertedChar, cursorPosition, text))
        {
            HandleText(text, cursorPosition);
        }
        ValidateRange(text, cursorPosition);
    }

    private bool IsInvalidInput(char insertedChar, int cursorPosition, string text)
    {
        return !char.IsDigit(insertedChar) && insertedChar != '.' && insertedChar != '-' ||
               insertedChar == '-' && cursorPosition != 0 ||
               text.Count(x => x == '.') > 1 ||
               text.Count(x => x == '-') > 1;
    }

    private void HandleText(string text, int cursorPosition)
    {
        this.Text = _flag ? _previousValue : text.Remove(cursorPosition, 1);
        this.SelectionStart = cursorPosition;
        this.SelectionLength = 0;
    }

    private void ValidateRange(string text, int cursorPosition)
    {
        try
        {
            if (text == "." || _minValue < 0 && text == "-") return;
            var doubleValue = Convert.ToDouble(text);
            if (doubleValue > _maxValue || doubleValue < _minValue)
            {
                HandleText(text, cursorPosition);
            }
        }
        catch (Exception)
        {
            HandleText(text, cursorPosition);
        }
    }

    protected void SetProperties(double minValue = double.MinValue, double maxValue = double.MaxValue)
    {
        _minValue = minValue;
        _maxValue = maxValue;
    }       

}

PositiveNumberTextBox 代码:

public class PositiveNumberTextBox : NumberTextBox
{
    public PositiveNumberTextBox()
    {
        SetProperties(0);
    }
}

分数文本框代码:

public class FractionNumberTextBox : NumberTextBox
{
    public FractionNumberTextBox()
    {
        SetProperties(0, 0.999999);
    }
}

这可以用于多行文本框吗?我想允许用户在多行上输入正双打
@SteveW,它不适用于多行文本。但是您可以在合并多行值后处理文本。
T
T.Rob
int Number;
bool isNumber;
isNumber = int32.TryPase(textbox1.text, out Number);

if (!isNumber)
{ 
    (code if not an integer);
}
else
{
    (code if an integer);
}

m
modest and cute girl

3 解决方案

1)

//Add to the textbox's KeyPress event
//using Regex for number only textBox

private void txtBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(), "\\d+"))
e.Handled = true;
}

2)msdn的另一个解决方案

// Boolean flag used to determine when a character other than a number is entered.
private bool nonNumberEntered = false;
// Handle the KeyDown event to determine the type of character entered into the     control.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
// Initialize the flag to false.
nonNumberEntered = false;
// Determine whether the keystroke is a number from the top of the keyboard.
if (e.KeyCode < Keys.D0 || e.KeyCode > Keys.D9)
{
    // Determine whether the keystroke is a number from the keypad.
    if (e.KeyCode < Keys.NumPad0 || e.KeyCode > Keys.NumPad9)
    {
        // Determine whether the keystroke is a backspace.
        if (e.KeyCode != Keys.Back)
        {
            // A non-numerical keystroke was pressed.
            // Set the flag to true and evaluate in KeyPress event.
            nonNumberEntered = true;
        }
    }
}

}

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (nonNumberEntered == true)
    {
       MessageBox.Show("Please enter number only..."); 
       e.Handled = true;
    }
}

来源http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress(v=VS.90).aspx

3) 使用 MaskedTextBox:http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx


请编辑解决方案 2...您在代码块外留下了“}”

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅