Лучший способ ограничить десятичный ввод текстового поля в C # - PullRequest
3 голосов
/ 27 июня 2010

Как сделать текстовое поле, в котором можно набирать только цифры вроде 12.00 или 1231231.00 или 123123

Я сделал это очень долго, и я ищу лучший и самый быстрый способ.

Кроме того, десятичный разделитель должен соответствовать конкретной культуре.

Application.CurrentCulture.NumberFormat.NumberDecimalSeparator

Ответы [ 4 ]

7 голосов
/ 27 июня 2010

Для этого было создано событие Validating. Удалите элемент управления ErrorProvider в своей форме, чтобы вы могли слегка напомнить пользователю, что она сделала что-то не так. Событие также позволяет вам форматировать текстовое поле так, как это имеет смысл. Как это:

    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");
            }
        }
    }
2 голосов
/ 22 июля 2010

Это довольно простая операция.Вам нужно будет отфильтровать ненужные ключи и затем выполнить некоторые дополнительные проверки.

Добавьте следующий код в событие 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;
    }
}

И затем, поскольку пользователь может вставить значения в текстовое поле, вы добавляете следующее в событие Validate TextBox

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

Я написал класс для обработки множества фильтров для вас [который, очевидно, включает в себяспецифичный для культуры десятичный символ].

Добавьте этот класс в свой проект

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

, а затем используйте его в своей форме следующим образом

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;
    }
}
0 голосов
/ 22 июля 2010
    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));
        }
    }

И вы должны проверить на Leave для длины == 0 Я думаю ...

0 голосов
/ 27 июня 2010

Попробуйте элемент управления MaskedTextBox .

...