Come faccio a creare una casella di testo che accetta solo numeri?


583

Ho un'app Windows Form con un controllo casella di testo che voglio accettare solo valori interi. In passato ho fatto questo tipo di convalida sovraccaricando l'evento KeyPress e rimuovendo i caratteri che non corrispondevano alle specifiche. Ho esaminato il controllo MaskedTextBox ma vorrei una soluzione più generale che potesse funzionare con un'espressione regolare o dipendere dai valori di altri controlli.

Idealmente, ciò si comporterebbe in modo tale che la pressione di un carattere non numerico non produca alcun risultato o fornisca immediatamente all'utente un feedback sul carattere non valido.


11
numeri o cifre? grande differenza: anche i numeri interi possono diventare negativi
Joel Coehoorn,

8
La domanda era rivolta ai numeri, compreso l'intero insieme di numeri razionali.
Mykroft,

Risposte:


797

Due opzioni:

  1. Usa NumericUpDowninvece un . NumericUpDown fa il filtro per te, il che è carino. Naturalmente offre anche ai tuoi utenti la possibilità di premere le frecce su e giù sulla tastiera per aumentare e diminuire il valore corrente.

  2. Gestisci gli eventi della tastiera appropriati per impedire qualsiasi input tranne quello numerico. Ho avuto successo con questi due gestori di eventi su un TextBox standard:

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

Puoi rimuovere il segno di spunta per '.'(e il controllo successivo per più di uno '.') se il tuo TextBox non dovrebbe consentire i decimali. È inoltre possibile aggiungere un controllo per verificare '-'se TextBox deve consentire valori negativi.

Se si desidera limitare l'utente per il numero di cifre, utilizzare: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits


5
L'unico inconveniente di NumericUpDown è che non fornisce alcun feedback quando si immette un valore al di fuori dei valori massimo o minimo consentiti: cambia solo ciò che è stato digitato. Una casella di testo può almeno consentire valori non validi in modo da poter avvisare l'utente quando invia il modulo.
Matt Hamilton,

7
È vero: l'utente può sempre incollare alcuni caratteri non numerici. Spereresti che la validazione del modulo lo capisca, dato che ad un certo punto vorrai fare un Int32. TryParse o qualcosa del genere.
Matt Hamilton,

52
Avrai bisogno di qualche sforzo aggiuntivo per globalizzare questo sostituendo i controlli per "." con controlli su CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
Jeff Yates,

6
@HamishGrubijan, IsControl non ha nulla a che fare con il tasto Control; restituisce se un carattere è o meno un carattere di controllo. Consentendo i caratteri di controllo, non rompi cose come backspace, delete o i tasti freccia
Thomas Levesque,

13
Ad ogni modo, accetta comunque input illegali ctrl + v; un bug che esiste persino nel controllo NumericUpDown ufficiale.
Nyerguds,

149

E solo perché è sempre più divertente fare cose in una riga ...

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

NOTA: Ciò NON impedisce a un utente di copiare / incollare in questa casella di testo. Non è un modo sicuro per disinfettare i tuoi dati.


questa non è una soluzione generale in quanto funziona solo per gli interger. Di recente ho dovuto implementare tale cosa e alla fine ho provato a analizzare la stringa risultante in numero e a consentire l'input solo se l'analisi è riuscita
grzegorz_p

1
Questo potrebbe non funzionare quando più metodi gestiscono KeyPresseventi dalla stessa casella di testo. Un evento potrebbe essere impostato e.Handledsu true, quindi un altro potrebbe riportarlo su false. In generale, è meglio usareif (...) e.Handled = true;
Nathaniel Jones

2
È possibile disabilitare la proprietà ShortcutsEnabled per impedire il copia e incolla dalla tastiera o dal menu
Ahmad,

3
Haha! Sì! Una fodera!
Jamie L.,

3
Eh. Un TextChangedevento che lo supera con un regex può correggere il copia-incolla;)
Nyerguds

51

Presumo dal contesto e dai tag che hai usato che stai scrivendo un'app .NET C #. In questo caso, è possibile iscriversi all'evento di modifica del testo e convalidare ciascun tasto.

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
Questo non darà un effetto molto strano se digiti nel mezzo di un numero?
Colin Pickard,

5
e inoltre dovrebbe essere:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
Pieniadz,

3
cosa succede se il primo carattere in sé non è una cifra ... non sottraendo 1 in quel caso
genererebbe

6
Inoltre, l'utilizzo di TextChanged anziché KeyPress crea un po 'di ricorsione in quanto il codice passerà a un secondo evento TextChanged dopo il metodo Remove.
WEFX,

2
Hai cambiato i parametri di input e pattern per la tua funzione IsMatch. L'input dovrebbe essere il primo, quindi il pattern. msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx
Mibou

36

Ecco un semplice controllo personalizzato Winforms autonomo, derivato dallo standard TextBox, che consente solo l'input System.Int32 (potrebbe essere facilmente adattato per altri tipi come System.Int64, ecc.). Supporta operazioni di copia / incolla e numeri negativi:

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

Aggiornamento 2017 : la mia prima risposta presenta alcuni problemi:

  • puoi digitare qualcosa che sia più lungo di un numero intero di un determinato tipo (ad esempio 2147483648 è maggiore di Int32.MaxValue);
  • più in generale, non esiste una vera validazione del risultato di ciò che è stato digitato;
  • gestisce solo int32, dovrai scrivere un controllo derivato TextBox specifico per ogni tipo (Int64, ecc.)

Quindi mi è venuta in mente un'altra versione più generica, che supporta ancora copia / incolla, + e - segno, ecc.

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

Per Int32, puoi derivarne da esso, in questo modo:

public class Int32TextBox : ValidatingTextBox
{
    protected override void OnTextValidating(object sender, TextValidatingEventArgs e)
    {
        e.Cancel = !int.TryParse(e.NewText, out int i);
    }
}

o senza derivazione, utilizzare il nuovo evento TextValidating in questo modo:

var vtb = new ValidatingTextBox();
...
vtb.TextValidating += (sender, e) => e.Cancel = !int.TryParse(e.NewText, out int i);

ma la cosa bella è che funziona con qualsiasi stringa e qualsiasi routine di validazione.


Questo è fantastico, carino e semplice, facilmente utilizzabile e gestisce insoliti tentativi di input. Grazie!
WiredEarp,

1
Nota sulla versione 2017, quando esiste un valore, ad esempio 1, e fai clic sul backspace, viene ignorato, mentre se avessi detto 120 e colpito il backspace tre volte ci rimane 1.
Karen Payne,

1
ValidatingTextbox è di gran lunga la migliore implementazione che ho visto per un po '. Semplice ed efficace Grazie!
Samuel,

19

Questo è esattamente ciò per cui sono stati progettati gli eventi convalidati / convalidanti.

Ecco l'articolo MSDN sull'argomento: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

La versione TL; DR: controlla la proprietà .Text nell'evento Validating e imposta e.Cancel=Truequando i dati non sono validi.

Quando imposti e.Cancel = True, l'utente non può lasciare il campo, ma dovrai dare loro una sorta di feedback che qualcosa non va. Cambio il colore di sfondo della scatola in rosso chiaro per indicare un problema. Assicurati di ripristinarlo SystemColors.Windowquando viene chiamato Convalida con un buon valore.


1
+1 per menzionare un approccio molto idiomatico API. Sono relativamente nuovo a Windows Form, ed è piuttosto una giungla di funzionalità e documenti MSDN, quindi grazie anche per il puntatore specifico a Validating. <nitpick>L'OP menziona che la disattivazione / indicazione immediata di un carattere invalidante è l'ideale, ma Validatingsembra richiedere che lo stato attivo venga spostato su un'altra forma / controllo prima che abbia effetto. </nitpick>Tuttavia, questo è un ottimo approccio e vale sempre la pena considerare nel caso più generale.
William,

13

Prova un MaskedTextBox . Prende un semplice formato maschera in modo da poter limitare l'input a numeri o date o altro.


2
In particolare non voglio usare un MaskedTextBox. I formati che consentono possono essere molto limitanti. Funzionano per questo caso, ma mi piacerebbe fare qualcosa di più generale.
Mykroft,

12

Puoi usare l' TextChangedevento

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

Sembra che dovrebbe funzionare bene se utilizzato Undo(), ma si traduce in un StackOverflowException.
Ha disegnato Chapin il

Sembra che la proprietà TextChanged sia parte della routine che si desidera annullare (). Ho una variabile per l'intera finestra e sto usando public int txtBoxValue, e se tryParse non funziona, ripristino il testo in txtBox ditxtBox.Text = txtBoxValue.ToString();
L. Zeda

8

Questo potrebbe essere utile Permette valori numerici "reali", inclusi punti decimali corretti e segni più o meno precedenti. Chiamalo dall'evento KeyPress correlato.

       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

Ho lavorato su una raccolta di componenti per completare elementi mancanti in WinForms, eccolo qui: Advanced Forms

In particolare questa è la classe per un TextBox Regex

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

Basta aggiungere qualcosa come myNumbericTextBox.RegexString = "^(\\d+|)$";dovrebbe essere sufficiente.


5

Basta usare un NumericUpDowncontrollo e impostare la brutta visibilità dei pulsanti su false.

numericUpDown1.Controls[0].Visible = false;

NumericUpDown è in realtà una raccolta di controlli contenente una "casella di selezione" (pulsanti su e giù), una casella di testo e del codice per convalidare e confondere tutto insieme.

Marcatura:

YourNumericUpDown.Controls[0].visible = false 

nasconderà i pulsanti mantenendo attivo il codice sottostante.

Pur non essendo una soluzione ovvia, è semplice ed efficace. .Controls[1]nasconderesti la parte della casella di testo se volessi farlo.


La risposta accettata non includeva alcuna informazione su come rimuovere i pulsanti su e giù, come farlo non è ovvio in quanto non esistono interfacce leggibili per abilitarli o disabilitarli. NumericUpDown è in realtà una raccolta di controlli che contiene una casella di testo e una "casella di selezione" (pulsanti su e giù) e alcuni codici di gestione della convalida dell'input.
user2163234

4

Ho fatto qualcosa per questo su CodePlex .

Funziona intercettando l'evento TextChanged. Se il risultato è un buon numero, verrà memorizzato. In caso di errore, verrà ripristinato l'ultimo valore valido. La fonte è un po 'troppo grande per essere pubblicata qui, ma qui c'è un collegamento alla classe che gestisce il nucleo di questa logica.


4

usa semplicemente questo codice nella casella di testo:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

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

4

Nella nostra pagina web con la definizione di casella di testo possiamo aggiungere un onkeypressevento per accettare solo numeri. Non mostrerà alcun messaggio ma ti impedirà di inserire erroneamente. Ha funzionato per me, l'utente non ha potuto inserire nulla tranne il numero.

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


2

Lo gestirò nell'evento KeyDown.

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

2
Che dire di tasti come "Backspace", "Elimina", "Freccia-Tasto-Sinistra", "Freccia-Tasto-Destra", Copia e incolla, Cifre inserite da Numpad (sono scambiate come!
Cifre

Basta aggiungere qualche altro test come questo: if (! Char.IsDigit (c) && c! = (Char) Keys.Back)
dnennis

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

prova questo è molto semplice


2

Dai un'occhiata alla gestione degli input in WinForm

Ho pubblicato la mia soluzione che utilizza gli eventi ProcessCmdKey e OnKeyPress nella casella di testo. I commenti mostrano come utilizzare un Regex per verificare la pressione dei tasti e bloccare / consentire in modo appropriato.


2

Ciao, puoi fare qualcosa del genere nell'evento modificato dalla casella di testo.

ecco una demo

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

Grazie, è molto utile.
Kiran RS,

2

Sembra che molte delle risposte attuali a questa domanda stiano analizzando manualmente il testo di input. Se stai cercando un tipo numerico incorporato specifico (ad esempio into double), perché non delegare il lavoro al TryParsemetodo di quel tipo ? Per esempio:

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

Se vuoi qualcosa di più generico ma ancora compatibile con il Designer di 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;
        }
    }
}

E infine, se vuoi qualcosa di completamente generico e non ti interessa il supporto di Designer:

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

È necessario accettare numeri interi e float, inclusi i numeri negativi.

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

Questo è il mio approccio:

  1. usando linq (filtro facile da modificare)
  2. copia / incolla il codice di prova
  3. mantiene la posizione del cursore quando si preme un personaggio proibito
  4. accetta gli zeri di sinistra
  5. e numeri di qualsiasi dimensione

    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

Utilizzando l'approccio descritto nella risposta di Fabio Iotti ho creato una soluzione più generica:

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", che contiene tutti i comportamenti di convalida non banali. Tutto ciò che resta da fare è ereditare da questa classe e sovrascrivere il metodo "IsValid" con qualsiasi logica di validazione richiesta. Ad esempio, utilizzando questa classe, è possibile creare "RegexedTextBox" che accetterà solo stringhe che corrispondono a espressioni regolari specifiche:

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

Successivamente, ereditando dalla classe "RegexedTextBox", possiamo facilmente creare i controlli "PositiveNumberTextBox" e "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

Mi dispiace svegliare i morti, ma pensavo che qualcuno potesse trovarlo utile per riferimenti futuri.

Ecco come lo gestisco. Gestisce numeri in virgola mobile, ma può essere facilmente modificato per numeri interi.

Fondamentalmente puoi solo premere 0 - 9 e .

Puoi avere solo uno 0 prima di .

Tutti gli altri caratteri vengono ignorati e la posizione del cursore viene mantenuta.

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

Ecco una versione int rapidamente modificata:

    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
Questa soluzione sta reinventando la ruota con avvertimenti. Localizzazione per esempio.
Julien Guertault,

1

Questo funziona con copia e incolla, trascina e rilascia, tasto giù, impedisce l'overflow ed è piuttosto semplice

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

Non dimenticare che un utente può incollare un testo non valido in a TextBox.

Se vuoi limitarlo, segui il codice seguente:

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

Stavo anche cercando il modo migliore per controllare solo i numeri nella casella di testo e il problema con la pressione dei tasti era che non supporta la copia incolla con il tasto destro o gli appunti, quindi ho trovato questo codice che convalida il momento in cui il cursore lascia il campo di testo e controlla anche campo vuoto. (versione adattata di 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 sembra una scelta davvero pessima da utilizzare per un evento.
LarsTech,

@LarsTech ciò che pensavo fosse cambiato anche nel testo può causare un messaggio di errore prima anche se l'utente realizza l'errore e prova a risolverlo, quindi ho pensato che avrei funzionato meglio. Quale pensi sia il miglior evento per questo caso?
Alston Antony,

@AlstonAntony commento in ritardo, lo so. Ma sarebbe sufficiente un semplice evento click che si attiva con il clic destro?
Takarii,

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 soluzione

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) un'altra soluzione da 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;
    }
}

fonte http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress(v=VS.90).aspx

3) utilizzando MaskedTextBox: http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx


0

Nel clic sul pulsante è possibile controllare il testo della casella di testo per il ciclo:

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

Risposta più semplice:

_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());
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.