Як зробити текстове поле, яке приймає лише номери?


582

У мене є додаток для форм Windows з керуванням текстовим полем, що я хочу приймати лише цілі значення. Раніше я робив подібну перевірку, перевантажуючи подію KeyPress і просто видаляючи символи, які не відповідали специфікації. Я переглянув елемент управління MaskedTextBox, але хотів би більш загальне рішення, яке могло б працювати з можливо регулярним виразом або залежати від значень інших елементів управління.

В ідеалі це поводиться так, що натискання символу, який не є числовим, або не дасть результату, або негайно надасть користувачеві зворотний зв'язок про недійсний символ.


11
числа чи цифри? велика різниця: навіть цілі числа можуть стати негативними
Joel Coehoorn

8
Питання було призначене для чисел, включаючи весь набір раціональних чисел.
Mykroft

Відповіді:


797

Два варіанти:

  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


5
Єдиний недолік NumericUpDown полягає в тому, що він не надає зворотного зв’язку, коли ви вводите значення за межами Максимальних або Мінімальних дозволених значень - він просто змінює те, що ви ввели. TextBox може хоча б дозволити недійсні значення, щоб ви могли попередити користувача, коли він надсилає форму.
Метт Гамільтон

7
Це правда - користувач завжди міг вставити деякі нечислові символи. Ви сподіваєтесь, що перевірка форми схопить це, оскільки в якийсь момент вам захочеться зробити Int32.TryParse чи щось таке.
Метт Гамільтон

52
Вам потрібно буде докласти додаткових зусиль, щоб глобалізувати це, замінивши чеки на "." з чеками на CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
Джефф Йейтс

6
@HamishGrubijan, IsControl не має нічого спільного з клавішею Control; він повертає, незалежно від того, чи це знак є контрольним. Дозволяючи керувати символами, ви не ламаєте такі речі, як повернення назад, видалення або клавіші зі стрілками
Thomas Levesque

13
Це, до речі, приймає незаконне введення ctrl + v; помилка, яка навіть існує в офіційному контролі NumericUpDown.
Nyerguds

149

І тільки тому, що завжди цікавіше робити речі в один рядок ...

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

ПРИМІТКА. Це НЕ перешкоджає користувачу скопіювати / вставити в це текстове поле. Це невдалий безпечний спосіб очистити свої дані.


це не загальне рішення, оскільки воно працює лише для інтергерів. Нещодавно мені довелося реалізувати таке, і я закінчив спробувати проаналізувати результуючу рядок на номер і дозволити введення лише у випадку успіху розбору
grzegorz_p

1
Це може не працювати, коли кілька методів обробляють KeyPressподії з одного текстового поля. Для однієї події може бути встановлено e.Handledзначення true, а потім інша зможе повернути її до false. Загалом, краще використовуватиif (...) e.Handled = true;
Натаніель Джонс

2
Ви можете відключити властивість ShortcutsEnabled, щоб запобігти вставці копій за допомогою клавіатури або меню
Ахмад

3
ХАХА! Так! Один лайнер!
Джеймі Л.

3
Е-е. TextChangedПодія , яке проходить через це з регулярним виразом може виправити копіпаст;)
Nyerguds

51

Я припускаю, що з контексту та тегів, які ви використовували, ви пишете додаток .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);
    }
}

22
Хіба це не дасть дуже дивного ефекту, якщо ви введете середину числа?
Колін Пікард

5
а також воно повинно бути:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
Pieniadz

3
що робити, якщо перший символ сам по собі не є цифрою ... не віднімає 1, у такому випадку викине помилку ....
manu_dilip_shah

6
Крім того, використання TextChanged замість KeyPress створює трохи рекурсії в тому, що код перейде у другий події TextChanged після методу Remove.
WEFX

2
Ви переключили параметри вводу та шаблону для своєї функції IsMatch. Введення має бути спочатку, а потім шаблоном. msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx
Мібу

36

Ось простий окремий користувальницький контроль 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, вам потрібно буде написати специфічний похідний TextBox для кожного типу (Int64 тощо)

Тому я придумав ще одну універсальну версію, яка все ще підтримує копіювати / вставляти, + та - підписувати тощо.

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

але що приємно, це те, що він працює з будь-яким рядком і будь-яким порядком перевірки.


Це чудово, приємно і просто, легко використовується і має справу з незвичними спробами введення. Дякую!
WiredEarp

1
Зверніть увагу на версію 2017 року, коли є одне значення, наприклад, 1, і ви натискаєте на простір, воно ігнорується, якщо, якщо ви сказали 120 і тричі вдарили назад, нам залишилось 1.
Карен Пейн

1
Ваш ValidatingTextbox - це далеко не найкраща реалізація, яку я бачив протягом певного часу. Простий і ефективний. Дякую!
Самуїл

19

Саме для цього були розраховані затверджені / перевірені події.

Ось стаття MSDN на тему: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

Версія TL; DR: перевірте властивість .Text у події Validating та встановіть, e.Cancel=Trueколи дані недійсні.

Якщо ви встановите e.Cancel = True, користувач не може залишити поле, але вам потрібно буде надати їм відгук про те, що щось не так. Я змінюю колір фону коробки на світло-червоний, щоб вказати на проблему. Переконайтеся, що поверніть його назад, SystemColors.Windowколи виклик перевірки з хорошим значенням.


1
+1 для згадування дуже API-ідіоматичного підходу. Я відносно новий в Windows Forms, і це досить джунглі функціональності та MSDN-документи, тому також дякую за конкретний вказівник doc на Validating. <nitpick>ОП згадує, що негайно заборонити / вказати недійсний символ є ідеальним, але, Validatingздається, вимагає, щоб фокус було переміщено до іншої форми / контролю, перш ніж воно набуває чинності. </nitpick>Все-таки це чудовий підхід і його завжди варто враховувати в більш загальному випадку.
Вільям

13

Спробуйте MaskedTextBox . Він має простий формат маски, щоб ви могли обмежити введення цифрами чи датами чи будь-яким іншим.


2
Я спеціально не хочу використовувати MaskedTextBox. Формати, які вони дозволяють, можуть бути дуже обмежуючими. Вони працюють у цій справі, але я хотів би зробити щось більш загальне.
Mykroft

12

Ви можете використовувати 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 відtxtBox.Text = txtBoxValue.ToString();
L. Zeda

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

6

Я працював над колекцією компонентів, щоб заповнити відсутні матеріали в WinForms, ось це: Розширені форми

Зокрема, це клас для Regex TextBox

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

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

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

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

        lastText = Text;

        base.OnTextChanged(e);
    }
}

Достатньо просто додати щось подібне myNumbericTextBox.RegexString = "^(\\d+|)$";.


5

Просто використовуйте NumericUpDownелемент керування та встановіть видимість цих потворних кнопок вниз false.

numericUpDown1.Controls[0].Visible = false;

NumericUpDown насправді - це сукупність елементів керування, що містять "відкручувану коробку" (кнопки вниз), текстове поле та деякий код, щоб перевірити та змістити все це разом.

Позначення:

YourNumericUpDown.Controls[0].visible = false 

приховає кнопки, зберігаючи основний код активним.

Хоча це не очевидне рішення, воно просте і ефективне. .Controls[1]приховав би частину текстового поля, якщо ви хочете це зробити замість цього.


Прийнята відповідь не містила жодної інформації про те, як видалити кнопки вгору вниз, як це зробити, не очевидно, оскільки немає людських читаних інтерфейсів, які б їх включали чи вимикали. NumericUpDown - це фактично сукупність елементів керування, що містять текстове поле та "відкручуване поле" (кнопки вниз) та деяку перевірку введення коду для обробки коду.
користувач2163234

4

Я щось зробив для цього на CodePlex .

Він працює, перехоплюючи подію TextChanged. Якщо результат хороший, він буде збережений. Якщо це щось не так, остання хороша цінність буде відновлена. Джерело трохи занадто велике, щоб опублікувати тут, але ось посилання на клас, який керує ядром цієї логіки.


4

просто використовуйте цей код у текстовому полі:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

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

4

На нашій веб-сторінці із визначенням текстового поля ми можемо додати onkeypressподію для прийому лише номерів. Він не відображатиме жодне повідомлення, але це запобіжить неправильному введенню даних. Це працювало для мене, користувач не міг ввести нічого, крім номера.

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

2

ви можете використовувати TextChanged / Keypress подію, використовувати регулярний вираз, щоб відфільтрувати числа та вжити певних дій.


2

Я би впорався з цим у заході KeyDown.

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

2
Як щодо клавіш, таких як "Backspace", "Delete", "Arrow-Key-Left", "Arrow-Key-Right", "Копіювати та вставляти", цифри, введені Numpad (вони торгуються як!
Цифра

Просто додайте ще кілька тестів на кшталт цього: якщо (! Char.IsDigit (c) && c! = (Char) Keys.Back)
деньnnis

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

спробувати це дуже просто


2

Подивись на обробку вводу в WinForm

Я розмістив своє рішення, яке використовує події ProcessCmdKey та OnKeyPress у текстовому полі. У коментарях показано, як використовувати Regex для перевірки натискання клавіші та блокування / дозволу належним чином.


2

Привіт, ви можете зробити щось подібне у події, що змінилася у текстовому вікні.

ось демонстрація

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

Дякую, дуже корисно.
Кіран РС

2

Схоже, багато поточних відповідей на це питання вручну аналізують вхідний текст. Якщо ви шукаєте певний вбудований числовий тип (наприклад, 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;
        }
    }
}

2

Як цілі числа, так і плавці потрібно прийняти, включаючи від’ємні числа.

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

2

Це мій підхід:

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

2

Використовуючи підхід, описаний у відповіді Фабіо Йотті, я створив більш загальне рішення:

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

1

Вибачте, що розбудив мертвих, але я подумав, що хтось може знайти це корисним для подальшого використання.

Ось як я впораюся. Він обробляє числа з плаваючою комою, але їх можна легко змінити для цілих чисел.

В основному ви можете натискати лише 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;
    }

2
Це рішення - винахід колеса із застереженнями. Наприклад, локалізація.
Жульєн Гурто

1

Цей працює з копіюванням та вставкою, перетягуванням, клавішею вниз, запобігає переповненню і досить простий

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

1

Не забувайте, що користувач може вставити недійсний текст у 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;
}   

1

Я також шукав найкращий спосіб перевірити лише цифри в текстовому полі та проблема з натисканням клавіші, чи не підтримує копіювальну пасту правою кнопкою миші або буфера обміну, тому придумав цей код, який перевіряє, коли курсор залишає текстове поле, а також перевіряє наявність порожнє поле. (адаптована версія newguy)

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

@LarsTech те, що, на мою думку, було змінено текстом, навіть може спричинити скриньку повідомлень про помилки, навіть якщо користувач зрозуміє помилку і спробує виправити її, щоб я подумав, що я буду працювати краще. Як ви вважаєте, що найкраща подія для цієї справи?
Елстон Ентоні

@AlstonAntony пізній коментар, я знаю. Але простого події клацання, яке активується правою кнопкою миші, було б досить?
Такарій

0
int Number;
bool isNumber;
isNumber = int32.TryPase(textbox1.text, out Number);

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

0

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


0

При натисканні кнопки ви можете перевірити текст текстового поля на предмет циклу:

char[] c = txtGetCustomerId.Text.ToCharArray();
bool IsDigi = true;

for (int i = 0; i < c.Length; i++)
     {
       if (c[i] < '0' || c[i] > '9')
      { IsDigi = false; }
     }
 if (IsDigi)
    { 
     // do something
    }

0

Простіша відповідь:

_textBox.TextChanged += delegate(System.Object o, System.EventArgs e)
{
    TextBox _tbox = o as TextBox;
    _tbox.Text = new string(_tbox.Text.Where(c => (char.IsDigit(c)) || (c == '.')).ToArray());
};
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.