简体   繁体   English

限制c#中文本框十进制输入的最佳方法

[英]Best way to limit textbox decimal input in c#

How can I make a textbox in which can be only typed a number like 12.00 or 1231231.00 or 123123 如何创建一个文本框,其中只能输入类似12.00或1231231.00或123123的数字

I've done this in a very long way and I'm looking for the best and fastest way. 我已经做了很长的事情,我正在寻找最好,最快的方式。

Also the decimal separator must be culture specific.: 小数分隔符也必须是特定于文化的:

Application.CurrentCulture.NumberFormat.NumberDecimalSeparator

The Validating event was made to do that. 验证事件是为了做到这一点。 Drop an ErrorProvider control on your form so you can subtly remind the user that she did something wrong. 删除表单上的ErrorProvider控件,以便巧妙地提醒用户她做错了什么。 The event also allows you to format the text box text the way that make sense. 该事件还允许您以有意义的方式格式化文本框文本。 Like this: 像这样:

    private void textBox1_Validating(object sender, CancelEventArgs e) {
        // Empty strings okay?  Up to you.
        if (textBox1.Text.Length > 0) {
            decimal value;
            if (decimal.TryParse(textBox1.Text, out value)) {
                textBox1.Text = value.ToString("N2");
                errorProvider1.SetError(textBox1, "");
            }
            else {
                e.Cancel = true;
                textBox1.SelectAll();
                errorProvider1.SetError(textBox1, "Please enter a number");
            }
        }
    }

That's a fairly straightforward operation. 这是一个相当简单的操作。 You'll need to filter the keys that you don't want out and then perform some additional checks. 您需要过滤掉您不想要的密钥,然后执行一些额外的检查。

Add the following code to the KeyDown event of the textbox: 将以下代码添加到文本框的KeyDown事件:

private void TextBox1_KeyDown(object sender, 
  System.Windows.Forms.KeyEventArgs e)
{
    switch (e.KeyCode) {
        case Keys.D0:
        case Keys.D1:
        case Keys.D2:
        case Keys.D3:
        case Keys.D4:
        case Keys.D5:
        case Keys.D6:
        case Keys.D7:
        case Keys.D8:
        case Keys.D9:
        case Keys.NumPad0:
      case Keys.NumPad1:
        case Keys.NumPad2:
        case Keys.NumPad3:
        case Keys.NumPad4:
        case Keys.NumPad5:
        case Keys.NumPad6:
        case Keys.NumPad7:
        case Keys.NumPad8:
        case Keys.NumPad9:
            //allow numbers only when no modifiers are active
            if (e.Control || e.Alt || e.Shift) {
                //suppress numbers with modifiers
                e.SuppressKeyPress = true;
                e.Handled = true;
                Interaction.Beep();
            }
            break;
           case (Keys)110:
        case Keys.OemPeriod:
            if (!((TextBox)sender).Text.Contains(".")) {
                //allow period key if there is no '.' 
                //in the text and no modifiers are active
                if (e.Control || e.Alt || e.Shift) {
                    //suppress numbers with modifiers
                    e.SuppressKeyPress = true;
                    e.Handled = true;
                    Interaction.Beep();
                }
            } else {
                e.SuppressKeyPress = true;
                e.Handled = true;
                Interaction.Beep();
            }
            break;
        case Keys.Subtract:
        case Keys.OemMinus:
            if (((TextBox)sender).SelectionStart == 0 && 
              !((TextBox)sender).Text.Contains("-")) {
                //allow the negative key only when the cursor 
                //is at the start of the textbox
                //and there are no minuses in the textbox
                //and no modifiers are active
                if (e.Control || e.Alt || e.Shift) {
                    //suppress numbers with modifiers
                    e.SuppressKeyPress = true;
                    e.Handled = true;
                    Interaction.Beep();
                }
            } else {
                e.SuppressKeyPress = true;
                e.Handled = true;
                Interaction.Beep();
            }
            break;
        case Keys.C:
        case Keys.X:
        case Keys.V:
        case Keys.Z:
            //allow copy, cut, paste & undo by checking for 
            //the CTRL state.
            if (e.Control == false) {
                e.SuppressKeyPress = true;
                e.Handled = true;
                Interaction.Beep();
            }
            break;
        case Keys.Control:
        case Keys.ControlKey:
        case Keys.Alt:
        case Keys.Shift:
        case Keys.ShiftKey:
            //allow control, alt & shift
            break;
        case Keys.Left:
        case Keys.Right:
        case Keys.Up:
        case Keys.Down:
        case Keys.PageUp:
        case Keys.PageDown:
        case Keys.Home:
        case Keys.End:
            //allow navigation keys
            break;
        case Keys.Back:
        case Keys.Delete:
            //allow backspace & delete
            break;
        default:
            //suppress any other key
            e.SuppressKeyPress = true;
            e.Handled = true;
            Interaction.Beep();
            break;
    }
}




And then, since a user may paste values into the textbox, you add the following to the TextBox's Validate event 然后,由于用户可以将值粘贴到文本框中,因此可以将以下内容添加到TextBox的Validate事件中

private void TextBox1_Validating(object sender, 
  System.ComponentModel.CancelEventArgs e)
{
    //just in case a value was pasted, 
    //we'll need to validate the value
    if (!Information.IsNumeric(((TextBox)sender).Text)) 
    {
        e.Cancel = true;
    }
}

I wrote a class to handle a variety of filters for you [which obviously includes the culture-specific decimal symbol]. 我写了一个类来为你处理各种过滤器[显然包括文化特定的小数符号]。

Add this class to your project 将此类添加到项目中

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class TextBoxFilter
{
    [Flags()]
    public enum Filters
    {
        None = 0,
        Text = 1,
        Numbers = 2,
        AlphaNumeric = Filters.Text | Filters.Numbers,
        Currency = 4,
        All = Filters.Text | Filters.Numbers | Filters.Currency
    }

    Dictionary<TextBox, Filters> _keyFilter;
    Dictionary<TextBox, string> _allowedKeys;
    Dictionary<TextBox, string> _invalidKeys;

    Dictionary<TextBox, Windows.Forms.KeyEventArgs> keyEventArgs;
    private static string DecimalMark = Application.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    private static string NegativeMark = Application.CurrentCulture.NumberFormat.NegativeSign;
    private static string CurrencySymb = Application.CurrentCulture.NumberFormat.CurrencySymbol;

    private static string CurrencyDecimal = Application.CurrentCulture.NumberFormat.CurrencyDecimalSeparator;

    public TextBoxFilter()
    {
        _keyFilter = new Dictionary<TextBox, Filters>();
        _allowedKeys = new Dictionary<TextBox, string>();
        _invalidKeys = new Dictionary<TextBox, string>();
        keyEventArgs = new Dictionary<TextBox, KeyEventArgs>();
    }

//set & remove filter

    public void SetTextBoxFilter(TextBox textBox, Filters filter)
    {
        SetTextBoxFilter(textBox, filter, AllowedKeys(textBox), InvalidKeys(textBox));
    }

    public void SetTextBoxFilter(TextBox textBox, string allowedKeys)
    {
        SetTextBoxFilter(textBox, Strings.Filter(textBox), allowedKeys, InvalidKeys(textBox));
    }


    public void SetTextBoxFilter(TextBox textBox, string allowedKeys, string invalidKeys)
    {
        SetTextBoxFilter(textBox, Strings.Filter(textBox), allowedKeys, invalidKeys);
    }


    public void SetTextBoxFilter(TextBox textBox, Filters filter, string allowedKeys, string invalidKeys)
    {
        if (!_keyFilter.ContainsKey(textBox)) {
            //add the textbox and its filter if it does not exist in 
            //the collection of registered textboxes
            _keyFilter.Add(textBox, filter);
            _allowedKeys.Add(textBox, allowedKeys);
            _invalidKeys.Add(textBox, invalidKeys);
            keyEventArgs.Add(textBox, new System.Windows.Forms.KeyEventArgs(Keys.None));

            //add the event handlers
            textBox.KeyDown += KeyDownUp;
            textBox.KeyUp += KeyDownUp;
            textBox.KeyPress += KeyPress;
            textBox.Validating += Validating;
            textBox.Disposed += Disposed;

        } else {
            //change the filter of the textbox if it exists in
            //the collection of registered textboxes
            _keyFilter(textBox) = filter;
            _allowedKeys(textBox) = allowedKeys;
            _invalidKeys(textBox) = invalidKeys;
        }
    }

    public void RemoveTextBoxFilter(TextBox textBox)
    {
        if (_keyFilter.ContainsKey(textBox)) {
            _keyFilter.Remove(textBox);
            _allowedKeys.Remove(textBox);
            _invalidKeys.Remove(textBox);
            keyEventArgs.Remove(textBox);

            textBox.KeyDown -= KeyDownUp;
            textBox.KeyUp -= KeyDownUp;
            textBox.KeyPress -= KeyPress;
            textBox.Validating -= Validating;
            textBox.Disposed -= Disposed;
        }
    }

    public bool ContainsTextBox(TextBox textBox)
    {
        return _keyFilter.ContainsKey(textBox);
    }

//properties

    public Filters Filter {
        get {
            if (ContainsTextBox(textBox)) {
                return _keyFilter.Item[textBox];
            } else {
                return Filters.None;
            }
        }
        set { SetTextBoxFilter(textBox, value); }
    }

    public string AllowedKeys {
        get {
            if (ContainsTextBox(textBox)) {
                return _allowedKeys(textBox);
            } else {
                return "";
            }
        }
        set { SetTextBoxFilter(textBox, this.Filter(textBox), value, this.InvalidKeys(textBox)); }
    }

    public string InvalidKeys {
        get {
            if (ContainsTextBox(textBox)) {
                return _invalidKeys(textBox);
            } else {
                return "";
            }
        }
        set { SetTextBoxFilter(textBox, this.Filter(textBox), this.AllowedKeys(textBox), value); }
    }

//event handlers

    private void Disposed(object sender, System.EventArgs e)
    {
        RemoveTextBoxFilter((TextBox)sender);
    }

    private void KeyDownUp(object sender, System.Windows.Forms.KeyEventArgs e)
    {
        //assign the modifiers
        keyEventArgs((TextBox)sender) = e;
    }

    private void KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
    {
        //ensure key pressed is in the allowed keys

        object txt = (TextBox)sender;
        object c = e.KeyChar;
        bool allowKey = IsValidChar(txt, c, txt.SelectionStart);


        //check for backspace & Ctrl combinations if the allowKey is still false
        if (allowKey == false) {
            if (keyEventArgs(txt).Control) {
                //control modifier goes with A, X, C, V and Z for 
                //Select All, Cut, Copy, Paste and Undo respectively
                object key = keyEventArgs(txt).KeyCode;
                allowKey = (key == Keys.A || key == Keys.X || key == Keys.C || key == Keys.V || key == Keys.Z);

            } else if (keyEventArgs(txt).KeyCode == Keys.Back) {
                //allow the backspace key
                allowKey = true;
            }
        }


        //disable the key if it was not valid
        if (!allowKey) {
            e.Handled = true;
            Interaction.Beep();
        }
    }

    private void Validating(object sender, System.ComponentModel.CancelEventArgs e)
    {
        object box = (TextBox)sender;
        object boxFlags = _keyFilter(box);

        //skip validation if the textbox allows all entries or there is no text
        if (boxFlags == Filters.All | string.IsNullOrEmpty(box.Text))
            return;

        //otherwise check the characters entered
        object txtChars = box.Text.ToCharArray;

        bool isValidEntry = false;

        //check each caracter for an invalid entry
        for (i = 0; i <= txtChars.Length - 1; i++) {
            object c = txtChars(i);
            isValidEntry = IsValidChar(box, txtChars(i), i);

            if (!isValidEntry) {
                box.Select(i, 1);
                break; // TODO: might not be correct. Was : Exit For
            }
        }

        if (!isValidEntry)
            e.Cancel = true;

        if (!isValidEntry) {
            Interaction.MsgBox("The text entered is invalid for the format " + boxFlags.ToString + "." + !string.IsNullOrEmpty(_allowedKeys(box)) ? Constants.vbCrLf + "Additional Allowed Keys: " + _allowedKeys(box) : "" + !string.IsNullOrEmpty(_invalidKeys(box)) ? Constants.vbCrLf + "Additional Invalid Keys: " + _invalidKeys(box) : "", MsgBoxStyle.Critical, "Invalid Entry");
        }
    }

    private bool IsValidChar(TextBox textBox, char c, int charIndex)
    {
        //ensure key pressed is in the allowed keys

        object pF = _keyFilter(textBox);
        object aK = _allowedKeys(textBox);
        object iK = _invalidKeys(textBox);
        bool shouldAllow = false;


        //if filter is set to all, return true unconditionally
        if (pF == Filters.All)
            return true;


        //check preset filters

        //check for text
        if (EnumHasFlag(pF, Filters.Text)) {
            if (!char.IsDigit(c)) {
                shouldAllow = true;
            } else {
                //if the character is a digit, check for the number flag (AlphaNumerics)
                if (EnumHasFlag(pF, Filters.Numbers)) {
                    shouldAllow = true;
                }
            }

        }

        //check for nubers
        if (shouldAllow == false && EnumHasFlag(pF, Filters.Numbers)) {
            if (char.IsDigit(c)) {
                shouldAllow = true;
            } else if (DecimalMark.Contains(c)) {
                //allow the decimal if there is no decimal in the textbox's
                //text or the selected text contains the mark
                if (!textBox.Text.Substring(0, charIndex).Contains(c) || textBox.SelectedText.Contains(c)) {
                    shouldAllow = true;
                }
            } else if (NegativeMark.Contains(c) && (charIndex <= NegativeMark.IndexOf(c))) {
                //allow the negative mark if we are at the start of the
                //textbox
                shouldAllow = true;
            }

        }

        //check for currency
        if (shouldAllow == false && EnumHasFlag(pF, Filters.Currency)) {
            if (char.IsDigit(c)) {
                shouldAllow = true;
            } else if (CurrencyDecimal.Contains(c)) {
                //allow the currency decimal mark if it does not exist in the
                //textbox's text or the selected text contains the mark
                if (!textBox.Text.Substring(0, charIndex).Contains(c) || textBox.SelectedText.Contains(c)) {
                    shouldAllow = true;
                }
            } else if (CurrencySymb.Contains(c) && (charIndex <= CurrencySymb.IndexOf(c))) {
                //allow the currency symbol if we are in a valid position
                shouldAllow = true;
            }

        }



        //now check for extra allowed keys
        if (!shouldAllow) {
            shouldAllow = aK.Contains(c);
        }

        //and then check for extra invalid keys
        if (shouldAllow && iK.Contains(c)) {
            shouldAllow = false;
        }


        return shouldAllow;
    }

    [System.Diagnostics.DebuggerStepThrough()]
    private bool EnumHasFlag(Enum value, Enum flag)
    {
        return (Convert.ToInt64(value) & Convert.ToInt64(flag)) == Convert.ToInt64(flag);
    }
}

and then use it in your form as follows 然后在表单中使用它,如下所示

public class Form1
{


    TextBoxFilter filter = new TextBoxFilter();
    private void Form1_Load(object sender, System.EventArgs e)
    {
        filter.SetTextBoxFilter(TextBox1, TextBoxFilter.Filters.Numbers);
    }
    public Form1()
    {
        Load += Form1_Load;
    }
}

尝试使用MaskedTextBox控件。

    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (!Char.IsNumber(e.KeyChar))
        {
            e.Handled = !(((TextBox)sender).SelectionStart != 0 && (e.KeyChar.ToString() == Application.CurrentCulture.NumberFormat.NumberDecimalSeparator && ((TextBox)sender).Text.IndexOf(Application.CurrentCulture.NumberFormat.NumberDecimalSeparator) == -1));
        }
    }

And you should check onLeave for Length == 0 I think... 你应该检查离开长度== 0我认为......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM