【问题标题】:How do I make a textbox that only accepts numbers?如何制作一个只接受数字的文本框?
【发布时间】:2010-10-02 13:47:13
【问题描述】:

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

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

【问题讨论】:

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

标签: c# .net winforms textbox


【解决方案1】:

两种选择:

  1. 请改用NumericUpDown。 NumericUpDown 为您进行过滤,这很好。当然,它还使您的用户能够点击键盘上的向上和向下箭头来增加和减少当前值。

  2. 处理适当的键盘事件以防止除数字输入之外的任何内容。我在标准 TextBox 上使用这两个事件处理程序取得了成功:

    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&
            (e.KeyChar != '.'))
        {
                e.Handled = true;
        }
    
        // only allow one decimal point
        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 控件中的错误。
【解决方案2】:

而且仅仅因为在一行中做事总是更有趣...

 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 使用正则表达式处理的事件可以修复复制粘贴;)
【解决方案3】:

我根据上下文和您使用的标签假设您正在编写一个 .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
【解决方案4】:

这是一个简单的独立 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 中实现它?
  • 你能让多行文本框的这项工作为真吗?我想在多行上允许正双打
【解决方案5】:

这正是 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 的特定文档指针。 &lt;nitpick&gt;OP 提到立即禁止/指示无效字符是理想的,但Validating 似乎需要在其生效之前将焦点移至另一个表单/控件。&lt;/nitpick&gt; 不过,这是一个很好的方法,而且总是在更一般的情况下值得考虑。
  • 这是一个很好的解决方案,因为需要最少的实现。值得注意的是,Validating 事件仅在控件失去焦点时发生。但是,很容易从按键调用相同的验证函数来进行实时验证。
【解决方案6】:

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

【讨论】:

  • 我特别不想使用 MaskedTextBox。他们允许的格式可能非常有限。他们适用于这种情况,但我想做一些更一般的事情。
【解决方案7】:

您可以使用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 中的文本
【解决方案8】:

这可能很有用。它允许“真实”数值,包括正确的小数点和前面的加号或减号。从相关的 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;
    }

【讨论】:

    【解决方案9】:

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

    尤其是正则表达式文本框的类

    /// <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+|)$"; 之类的内容就足够了。

    【讨论】:

      【解决方案10】:

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

      numericUpDown1.Controls[0].Visible = false;
      

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

      标记:

      YourNumericUpDown.Controls[0].visible = false 
      

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

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

      【讨论】:

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

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

      private void textBox1_TextChanged(object sender, EventArgs e)
      {
      
          double parsedValue;
      
          if (!double.TryParse(textBox1.Text, out parsedValue))
          {
              textBox1.Text = "";
          }
      }
      

      【讨论】:

        【解决方案12】:

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

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

        【讨论】:

          【解决方案13】:

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

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

          【讨论】:

            【解决方案14】:

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

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

            【讨论】:

              【解决方案15】:

              这是我的方法:

              1. 使用 linq(易于修改过滤器)
              2. 复制/粘贴验证码
              3. 按禁止字符时保持插入符号位置
              4. 接受左零
              5. 以及任何尺寸的数字

                private void numeroCuenta_TextChanged(object sender, EventArgs e)
                {
                    string org = numeroCuenta.Text;
                    string formated = string.Concat(org.Where(c => (c >= '0' && c <= '9')));
                    if (formated != org)
                    {
                        int s = numeroCuenta.SelectionStart;
                        if (s > 0 && formated.Length > s && org[s - 1] != formated[s - 1]) s--;
                        numeroCuenta.Text = formated;
                        numeroCuenta.SelectionStart = s;
                    }
                }
                

              【讨论】:

                【解决方案16】:

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

                【讨论】:

                  【解决方案17】:

                  我会在 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 输入的数字之类的键呢(它们被交易为!数字)
                  • 只需添加一些类似这样的测试:if (!char.IsDigit(c) && c != (char)Keys.Back)
                  【解决方案18】:
                  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;
                          }
                      }
                  }
                  

                  试试这个很简单

                  【讨论】:

                    【解决方案19】:

                    看看Input handling in WinForm

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

                    【讨论】:

                      【解决方案20】:

                      您好,您可以在文本框的 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;
                          }
                      

                      【讨论】:

                      • 谢谢,非常有用。
                      【解决方案21】:

                      似乎这个问题的许多当前答案都是手动解析输入文本。如果您正在寻找特定的内置数​​字类型(例如 int 或 double),为什么不将工作委托给该类型的 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;
                              }
                          }
                      }
                      

                      最后,如果您想要完全通用的东西并且不关心设计器支持:

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

                      【讨论】:

                        【解决方案22】:

                        使用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*$") { }
                        }
                        

                        【讨论】:

                          【解决方案23】:

                          这是使用 .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 _);
                          }
                          

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

                          【讨论】:

                          • 我正在寻找一种在多行文本框中允许正整数/双精度数的方法。你的方法能做到吗?
                          【解决方案24】:

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

                          这是我的处理方式。它处理浮点数,但可以轻松修改为整数。

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

                          【讨论】:

                          • 这个解决方案是在重新发明轮子,但需要注意。例如本地化。
                          • 在允许多行的情况下你会怎么做?
                          【解决方案25】:

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

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

                          【讨论】:

                            【解决方案26】:

                            不要忘记用户可以在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;
                            }   
                            

                            【讨论】:

                              【解决方案27】:

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

                              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 迟到的评论,我知道。但是在右键单击时激活的简单单击事件就足够了,不是吗?
                              【解决方案28】:

                              这里有 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);
                                  }
                              }
                              

                              FractionNumberTextBox 代码:

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

                              【讨论】:

                              • 这可以用于多行文本框吗?我想允许用户在多行上输入正双打
                              • @SteveW,它不适用于多行文本。但是您可以在合并多行值后处理文本。
                              【解决方案29】:
                              int Number;
                              bool isNumber;
                              isNumber = int32.TryPase(textbox1.text, out Number);
                              
                              if (!isNumber)
                              { 
                                  (code if not an integer);
                              }
                              else
                              {
                                  (code if an integer);
                              }
                              

                              【讨论】:

                                【解决方案30】:

                                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...您在代码块外留下了一个“}”
                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2022-06-28
                                • 2011-06-15
                                • 1970-01-01
                                • 1970-01-01
                                • 2012-02-19
                                • 2015-12-30
                                相关资源
                                最近更新 更多