C# 如何强制在 maskedtextbox 中只允许数字值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10758683/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 15:08:44  来源:igfitidea点击:

How to Force only numeric values be allowed in maskedtextbox?

c#.netwinforms

提问by Rac Main

I am fairly new to Winforms, and I would like to know how to use a MaskedTextBox to ensure that only numerical values(decimals included) are entered by the user.

我是 Winforms 的新手,我想知道如何使用 MaskedTextBox 来确保用户只输入数值(包括小数)。

I have tried the masked feature using "/^[-+]?[0-9]+(.[0-9]+)?$/" and was not successful with that. What I want, even if with an ordinary textbox, is to allow only numerals/decimal values

我已经尝试过使用 "/^[-+]?[0-9]+(.[0-9]+)?$/" 的屏蔽功能,但没有成功。我想要的是,即使使用普通文本框,也只允许数字/十进制值

采纳答案by Chuck Savage

I adapted this NumericTextBox control: http://sanity-free.org/forum/viewtopic.php?pid=1205#p1205

我调整了这个 NumericTextBox 控件:http://sanity-free.org/forum/viewtopic.php?pid=1205#p1205

If you want it apart of your toolbox, you'd probably create a new control based on a TextBox and paste the code in that link into the code section.

如果您希望将其与工具箱分开,您可能会基于 TextBox 创建一个新控件并将该链接中的代码粘贴到代码部分。

Here's my version of it. I don't know how much I've modified it as I've had it a long time.

这是我的版本。我不知道我修改了多少,因为我已经用了很长时间了。

NumericTextBox.Designer.cs:

NumericTextBox.Designer.cs:

using System.Windows.Forms;

namespace SeaRisenLib2.Controls
{
    partial class NumericTextBox : TextBox
    {
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
            //this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        }

        #endregion
    }
}

NumericTextBox.cs

数字文本框.cs

// From: http://sanity-free.org/forum/viewtopic.php?pid=1205#p1205
// modified it slightly
//
/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  NumericTextBox Library                            */
/*  by: Steve Whitley                                 */
/*  ? 2005 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/
/* Changed by Carlos Montiers                         */
/* Decimal separator "." or "," depending on locale   */
/* Constructor for numericTextBox whith or without    */
/* negative range and number of decimals.             */
/* Does not allow the entry of non-numeric character  */
/* through alt + ascii code                           */
/* Permit use of tab key                              */
/* Version: 24-10-2008                                */
/******************************************************/

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace SeaRisenLib2.Controls
{
    public partial class NumericTextBox : TextBox
    {
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_PASTE = 0x0302;
        private int decimalNumbers;
        private bool hasNegatives;
        private string format;

        public delegate void D(NumericTextBox sender);
        /// <summary>
        /// Fired when Text changes
        /// </summary>
        public event D Changed = delegate { };

        /// <summary>
        /// Constructor of a NumericTextBox, with negative number and 2 decimals.
        /// </summary>
        public NumericTextBox()
            : this(2, true)
        {
        }

        /// <summary>
        /// Constructor with parameters
        /// </summary>
        /// <param name="decimalNumbers">number of decimals</param>
        /// <param name="hasNegatives">has negatives</param>
        public NumericTextBox(int decimalNumbers, bool hasNegatives)
            : base()
        {
            InitializeComponent();
            DecimalNumbers = decimalNumbers;
            HasNegatives = hasNegatives;
            Format = Format;
        }

        /// <summary>
        /// Property of decimalNumbers
        /// </summary>
        public int DecimalNumbers
        {
            get
            {
                return decimalNumbers;
            }
            set
            {
                decimalNumbers = value > 0 ? value : 0;
            }
        }

        /// <summary>
        /// Bindable Decimal Text
        /// </summary>
        public decimal DecimalText
        {
            get {
                if(string.IsNullOrEmpty(Text))
                    return 0;

                return Convert.ToDecimal(Text);
            }
            set { Text = value.ToString(); }
        }

        /// <summary>
        /// The string text value of the numeric text, use DecimalText to get the numeric value.
        /// </summary>
        public override string Text
        {
            get { return base.Text; }
            set
            {
                base.Text = value;
                Changed(this);
            }
        }

        /// <summary>
        /// Property of hasNegatives
        /// </summary>
        public bool HasNegatives
        {
            get
            {
                return hasNegatives;
            }
            set
            {
                hasNegatives = value;
            }
        }

        /// <summary>
        /// Property of format
        /// </summary>
        public string Format
        {
            get
            {
                return format;
            }
            set
            {
                format = "^";
                format += HasNegatives ? "(\" + getNegativeSign() + "?)" : "";
                format += "(\d*)";
                if (DecimalNumbers > 0)
                {
                    format += "(\" + getDecimalSeparator() + "?)";
                    for (int i = 1; i <= DecimalNumbers; i++)
                    {
                        format += "(\d?)";
                    }
                }
                format += "$";
            }
        }

        /// <summary>
        /// Method PreProcessMessage
        /// </summary>
        /// <param name="msg">ref Message</param>
        /// <returns>bool</returns>
        public override bool PreProcessMessage(ref Message msg)
        {
            if (msg.Msg == WM_KEYDOWN)
            {
                Keys keys = (Keys)msg.WParam.ToInt32();

                bool numbers = ModifierKeys != Keys.Shift
                                && (keys >= Keys.D0 && keys <= Keys.D9
                                    || (keys >= Keys.NumPad0 && keys <= Keys.NumPad9));


                bool dec = ModifierKeys != Keys.Shift
                            && (keys == Keys.Decimal
                                || keys == Keys.Oemcomma
                                || keys == Keys.OemPeriod);

                bool negativeSign = (keys == Keys.OemMinus && ModifierKeys != Keys.Shift)
                                    || keys == Keys.Subtract;

                bool home = keys == Keys.Home;
                bool end = keys == Keys.End;

                bool ctrlZ = keys == Keys.Z && ModifierKeys == Keys.Control;
                bool ctrlX = keys == Keys.X && ModifierKeys == Keys.Control;
                bool ctrlC = keys == Keys.C && ModifierKeys == Keys.Control;
                bool ctrlV = keys == Keys.V && ModifierKeys == Keys.Control;

                bool del = keys == Keys.Delete;
                bool bksp = keys == Keys.Back;

                bool tab = keys == Keys.Tab;

                bool arrows = keys == Keys.Up
                              || keys == Keys.Down
                              || keys == Keys.Left
                              || keys == Keys.Right;

                if (numbers || del || bksp || arrows || home || end
                    || ctrlC || ctrlX || ctrlV || ctrlZ)
                {
                    return false;
                }
                else
                {
                    if (dec)
                    {
                        return DecimalNumbers <= 0;
                    }
                    else
                    {
                        if (negativeSign)
                        {
                            return !HasNegatives;
                        }
                        else
                        {
                            if (tab)
                            {
                                return base.PreProcessMessage(ref msg);
                            }
                            else
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            else
            {
                return base.PreProcessMessage(ref msg);
            }
        }

        /// <summary>
        /// Method WndProc
        /// </summary>
        /// <param name="m">ref Message</param>
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_PASTE)
            {
                IDataObject obj = Clipboard.GetDataObject();
                string input = (string)obj.GetData(typeof(string));
                string pasteText = getPosibleText(input);

                if (!isValidadFormat(pasteText))
                {
                    m.Result = (IntPtr)0;
                    return;
                }
            }
            base.WndProc(ref m);
        }

        /// <summary>
        /// Method OnKeyPress
        /// </summary>
        /// <param name="e">KeyPressEventArgs</param>
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);
            string keyInput = e.KeyChar.ToString();
            string inputText = getPosibleText(keyInput);

            if (Char.IsDigit(e.KeyChar)
                || keyInput.Equals(getDecimalSeparator())
                || keyInput.Equals(getNegativeSign()))
            {
                e.Handled = !isValidadFormat(inputText);
            }
            else if (e.KeyChar == '\b'
                    || e.KeyChar == '\t'
                    || keyInput.Equals(Keys.Delete.ToString())
                    || keyInput.Equals(Keys.Home.ToString())
                    || keyInput.Equals(Keys.End.ToString()))
            {
                //Allow backspace, tab, delete, home, end
            }
            else if (e.KeyChar == 26
                     || e.KeyChar == 24
                     || e.KeyChar == 3
                     || e.KeyChar == 22)
            {
                // 26 : Allow Ctrl+Z | 24 : Allow Ctrl+X
                //  3 : Allow Ctrl+C | 22 : Allow Ctrl+V
            }
            else
            {
                //Disallow
                e.Handled = true;
            }
        }

        /// <summary>
        /// Method OnTextChanged
        /// </summary>
        /// <param name="e">System.EventArgs</param>
        protected override void OnTextChanged(System.EventArgs e)
        {
            if (getFloatValue() < 0)
            {
                this.ForeColor = Color.Red;
            }
            else
            {
                this.ForeColor = Color.Black;
            }

            //If the decimal point is preceded by a no number is added zero
            if (this.Text.StartsWith(getNegativeSign() + getDecimalSeparator()))
            {
                this.Text = getNegativeSign() + "0" + this.Text.Substring(1);
                this.Select(3, 0);
            }
            else
            {
                if (this.Text.StartsWith(getDecimalSeparator()))
                {
                    this.Text = "0" + this.Text;
                    this.Select(2, 0);
                }
            }
            base.OnTextChanged(e);
        }

        /// <summary>
        /// Method for validate text with format
        /// </summary>
        /// <param name="text">text</param>
        /// <returns>is valid format</returns>
        private bool isValidadFormat(string text)
        {
            return Regex.IsMatch(text, Format);
        }

        /// <summary>
        /// Method for get deciamal separator
        /// </summary>
        /// <returns>Decimal Separator of current culture</returns>
        private string getDecimalSeparator()
        {
            return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
        }

        /// <summary>
        /// Method for get negative sign
        /// </summary>
        /// <returns>Negative Sign of current culture</returns>
        private string getNegativeSign()
        {
            return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeSign;
        }

        /// <summary>
        /// Method for get posible resulting text for input text
        /// </summary>
        /// <param name="text">string with input text</param>
        /// <returns>posible text</returns>
        private string getPosibleText(string text)
        {
            string rText;
            rText = this.Text.Substring(0, SelectionStart);
            rText += text;
            rText += this.Text.Substring(SelectionStart + SelectionLength);
            return rText;
        }

        /// <summary>
        /// Method for get int value of text
        /// </summary>
        /// <returns>int value</returns>
        public int getIntValue()
        {
            try
            {
                return (int)getFloatValue();
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// Method for get round int value of text
        /// </summary>
        /// <returns>round int value</returns>
        public int getIntRoundValue()
        {
            try
            {
                return (int)Math.Round(getFloatValue());
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// Method for get float value of text
        /// </summary>
        /// <returns>float value</returns>
        public float getFloatValue()
        {
            try
            {
                return float.Parse(this.Text);
            }
            catch
            {
                return 0;
            }
        }


    }
}

回答by J...

Why not just use a NumericUpDown? Set your max and min values, number of decimal places, and away you go.

为什么不直接使用 NumericUpDown?设置您的最大值和最小值、小数位数,然后就可以了。

http://msdn.microsoft.com/en-us/library/system.windows.forms.numericupdown%28v=vs.90%29.aspx

http://msdn.microsoft.com/en-us/library/system.windows.forms.numericupdown%28v=vs.90%29.aspx

回答by KeithS

Masks for the MaskedTextBox aren't regex patterns; they use their own syntax.

MaskedTextBox 的掩码不是正则表达式模式;他们使用自己的语法。

The pattern you want is probably something like "999,990.9999". This requires the user to enter at least one digit, but they can enter any number from 0 to 999,999.9999 and with up to 4 decimals precision, and will automatically insert the thousands separator when needed.

您想要的模式可能类似于“999,990.9999”。这要求用户至少输入一位数字,但他们可以输入 0 到 999,999.9999 之间的任意数字,最多可输入 4 位小数,并在需要时自动插入千位分隔符。

Another thing you can do, similar to what the MaskedTextBox itself does, is override OnKeyPress to reject any character entered that would cause a Regex not to match:

您可以做的另一件事,类似于 MaskedTextBox 本身所做的,是覆盖 OnKeyPress 以拒绝输入的任何会导致 Regex 不匹配的字符:

public class RegexTextBox:TextBox
{
   [Category("Behavior")]
   public string RegexPattern {get;set;}

   protected override OnKeyPress(KeyPressEventArgs e)
   { 
      if (!Regex.IsMatch(this.Text + e.KeyChar, RegexPattern)) e.Handled = true;
      else base.OnKeyPress(e);
   }
}

You have to be careful when defining the pattern, because it will only work if what's been entered so far matches the pattern. However, it will work in your case, if you use a pattern like "[0-9]{1,3}((,[0-9]{1,3})*(\.[0-9]*)?".

定义模式时必须小心,因为只有到目前为止输入的内容与模式匹配时,它才会起作用。但是,如果您使用像"[0-9]{1,3}((,[0-9]{1,3})*(\.[0-9]*)?".

回答by Krzysztof Radzimski

thanks , working code below.

谢谢,下面的工作代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace System.Windows.Forms {
    public class RegexTextBox : TextBox {
        [Category("Behavior")]
        public string RegexPattern { get; set; }
        private bool DelOrBack = false;
        protected override void OnKeyDown(KeyEventArgs e) {
            base.OnKeyDown(e);
            if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) {
                DelOrBack = true;
            }
        }

        protected override void OnKeyPress(KeyPressEventArgs e) {
            if (!Regex.IsMatch(this.Text + e.KeyChar, RegexPattern) && !DelOrBack) {
                e.Handled = true;               
            }
            else {
                base.OnKeyPress(e);
            }

            DelOrBack = false;
        }
    }

    public class NumericTextBox : RegexTextBox {
        public NumericTextBox() {
            RegexPattern = "^[0-9]+$";
        }
    }
}