¿Cómo hago un cuadro de texto que solo acepta números?


583

Tengo una aplicación de formularios de Windows con un control de cuadro de texto que solo quiero aceptar valores enteros. En el pasado, he realizado este tipo de validación sobrecargando el evento KeyPress y simplemente eliminando caracteres que no se ajustaban a la especificación. He examinado el control MaskedTextBox, pero me gustaría una solución más general que podría funcionar con una expresión regular o depender de los valores de otros controles.

Idealmente, esto se comportaría de manera tal que presionar un carácter no numérico no produciría ningún resultado o proporcionaría inmediatamente al usuario comentarios sobre el carácter no válido.


11
números o dígitos? gran diferencia: incluso los enteros pueden ser negativos
Joel Coehoorn

8
La pregunta estaba destinada a números que incluyen todo el conjunto de números racionales.
Mykroft

Respuestas:


797

Dos opciones:

  1. Use un NumericUpDownen su lugar. NumericUpDown hace el filtrado por usted, lo cual es bueno. Por supuesto, también brinda a sus usuarios la capacidad de presionar las flechas hacia arriba y hacia abajo en el teclado para aumentar y disminuir el valor actual.

  2. Maneje los eventos de teclado apropiados para evitar cualquier cosa que no sea entrada numérica. He tenido éxito con estos dos controladores de eventos en un TextBox estándar:

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

Puede eliminar la comprobación de '.'(y la comprobación posterior de más de uno '.') si su TextBox no debe permitir lugares decimales. También puede agregar una verificación para ver '-'si su TextBox debe permitir valores negativos.

Si desea limitar el número de dígitos al usuario, use: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits


55
El único inconveniente con NumericUpDown es que no proporciona comentarios cuando ingresa un valor fuera de los valores máximos o mínimos permitidos, solo cambia lo que ha escrito. Un TextBox puede al menos permitir valores no válidos para que pueda advertir al usuario cuando envíe el formulario.
Matt Hamilton el

77
Eso es cierto: el usuario siempre puede pegar algunos caracteres no numéricos. Sin embargo, es de esperar que la validación del formulario capte eso, ya que en algún momento querrás hacer un Int32. TryParse o algo así.
Matt Hamilton el

52
Necesitará un esfuerzo adicional para globalizar esto al reemplazar los cheques por '.' con verificaciones en CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
Jeff Yates el

66
@HamishGrubijan, IsControl no tiene nada que ver con la tecla Control; devuelve si un char es o no un control char. Al permitir caracteres de control, no se rompen cosas como retroceso, eliminación o las teclas de flecha
Thomas Levesque

13
Esto todavía acepta la entrada ilegal de ctrl + v, por cierto; un error que incluso existe en el control oficial NumericUpDown.
Nyerguds

149

Y solo porque siempre es más divertido hacer cosas en una línea ...

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

NOTA: Esto NO impide que un usuario copie / pegue en este cuadro de texto. No es una forma segura de desinfectar sus datos.


Esta no es una solución general, ya que funciona solo para los enteros. Tenía que poner en práctica tal cosa hace poco y que terminó con try-análisis resultante cadena a número y permitir la entrada sólo si el análisis tuvo éxito
grzegorz_p

1
Esto puede no funcionar cuando varios métodos manejan KeyPresseventos desde el mismo cuadro de texto. Un evento podría establecerse e.Handleden verdadero, y luego otro podría volver a establecerlo en falso. En general, es mejor usarif (...) e.Handled = true;
Nathaniel Jones

2
Puede deshabilitar la propiedad ShortcutsEnabled para evitar copiar y pegar con el teclado o el menú
Ahmad

3
¡JAJA! ¡Si! ¡Una camisa!
Jamie L.

3
Eh Un TextChangedevento que lo supera con una expresión regular puede arreglar copiar y pegar;)
Nyerguds

51

Supongo por contexto y las etiquetas que usó que está escribiendo una aplicación .NET C #. En este caso, puede suscribirse al evento de cambio de texto y validar cada pulsación de tecla.

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
¿No va a dar un efecto muy extraño si escribes en el medio de un número?
Colin Pickard

55
y también debería ser:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
Pieniadz

3
¿Qué pasa si el primer carácter en sí mismo no es un dígito ... no restaría 1 en ese caso arrojaría un error ...
manu_dilip_shah

66
Además, el uso de TextChanged en lugar de KeyPress crea un poco de recursión en el sentido de que el código saltará a un segundo evento TextChanged después del método Remove.
WEFX

2
Cambió los parámetros de entrada y patrón para su función IsMatch. La entrada debe ser primero, luego patrón. msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx
Mibou

36

Aquí hay un control personalizado de Winforms simple e independiente, derivado del cuadro de texto estándar, que solo permite la entrada System.Int32 (podría adaptarse fácilmente para otros tipos como System.Int64, etc.). Admite operaciones de copiar / pegar y números negativos:

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

Actualización 2017 : mi primera respuesta tiene algunos problemas:

  • puede escribir algo que sea más largo que un número entero de un tipo dado (por ejemplo, 2147483648 es mayor que Int32.MaxValue);
  • en general, no existe una validación real del resultado de lo que se ha escrito;
  • solo maneja int32, tendrá que escribir un control derivado TextBox específico para cada tipo (Int64, etc.)

Así que se me ocurrió otra versión que es más genérica, que todavía admite copiar / pegar, + y - firmar, etc.

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

Para Int32, puede derivar de él, así:

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

o sin derivación, use el nuevo evento TextValidating como este:

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

pero lo bueno es que funciona con cualquier cadena y cualquier rutina de validación.


Esto es genial, agradable y simple, fácil de usar y trata con intentos de entrada inusuales. ¡Gracias!
WiredEarp

1
Nota sobre la versión 2017, cuando hay un valor, por ejemplo, 1 y pulsa el retroceso, se ignora, mientras que si dijera 120 y pulsa el retroceso tres veces, nos queda 1.
Karen Payne

1
Su ValidatingTextbox es, con mucho, la mejor implementación que he visto en mucho tiempo. Simple y efectivo. ¡Gracias!
Samuel

19

Esto es exactamente para lo que se diseñaron los eventos Validated / Validating.

Aquí está el artículo de MSDN sobre el tema: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

La versión TL; DR: verifique la propiedad .Text en el evento Validating y configure e.Cancel=Truecuando los datos no sean válidos.

Cuando configura e.Cancel = True, el usuario no puede abandonar el campo, pero tendrá que darles algún tipo de retroalimentación de que algo está mal. Cambio el color de fondo del cuadro a rojo claro para indicar un problema. Asegúrese de volver a establecerlo SystemColors.Windowcuando se llame a Validar con un buen valor.


1
+1 por mencionar un enfoque muy idiomático API. Soy relativamente nuevo en Windows Forms, y es una jungla de funcionalidad y documentos de MSDN, así que también gracias por el puntero de documento específico Validating. <nitpick>El OP menciona que lo ideal es rechazar / indicar de inmediato un carácter invalidante, pero Validatingparece requerir que el foco se mueva a otra forma / control antes de que surta efecto. </nitpick>Aún así, este es un gran enfoque y siempre vale la pena considerarlo en el caso más general.
William

13

Prueba un MaskedTextBox . Toma un formato de máscara simple para que pueda limitar la entrada a números o fechas o lo que sea.


2
Específicamente no quiero usar un MaskedTextBox. Los formatos que permiten pueden ser muy limitantes. Funcionan para este caso, pero me gustaría hacer algo más general.
Mykroft

12

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

Parece que debería funcionar bien si lo usó Undo(), pero resulta en un StackOverflowException.
Drew Chapin

Parece que la propiedad TextChanged es parte de la rutina que desea deshacer (). Tengo una variable para toda la ventana y estoy usando public int txtBoxValue, y si tryParse no funciona, revierto el texto en txtBox portxtBox.Text = txtBoxValue.ToString();
L. Zeda

8

Esto puede ser útil. Permite valores numéricos "reales", incluidos los puntos decimales adecuados y los signos más o menos anteriores. Llámalo desde el evento KeyPress relacionado.

       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

He estado trabajando en una colección de componentes para completar las cosas que faltan en WinForms, aquí está: Formularios avanzados

En particular, esta es la clase para un 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);
    }
}

Simplemente agregar algo como myNumbericTextBox.RegexString = "^(\\d+|)$";debería ser suficiente.


5

Simplemente use un NumericUpDowncontrol y configure la visibilidad de esos botones feos hacia arriba false.

numericUpDown1.Controls[0].Visible = false;

NumericUpDown en realidad es una colección de controles que contiene un 'cuadro giratorio' (botones arriba-abajo), un cuadro de texto y un código para validar y juntar todo.

Calificación:

YourNumericUpDown.Controls[0].visible = false 

ocultará los botones mientras mantiene activo el código subyacente.

Si bien no es una solución obvia, es simple y eficaz. .Controls[1]ocultaría la parte del cuadro de texto si quisieras hacer eso en su lugar.


La respuesta aceptada no incluía ninguna información sobre cómo eliminar los botones de arriba hacia abajo, no es obvio cómo hacerlo, ya que no hay interfaces legibles por humanos para habilitarlas o deshabilitarlas. NumericUpDown es en realidad una colección de controles que contiene un cuadro de texto y un "cuadro giratorio" (botones arriba abajo) y algunas validaciones de entrada de manejo de código.
user2163234

4

He hecho algo para esto en CodePlex .

Funciona interceptando el evento TextChanged. Si el resultado es un buen número, se almacenará. Si algo está mal, se restaurará el último buen valor. La fuente es demasiado grande para publicar aquí, pero aquí hay un enlace a la clase que maneja el núcleo de esta lógica.


4

simplemente use este código en el cuadro de texto:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

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

4

En nuestra página web con la definición de cuadro de texto, podemos agregar un onkeypressevento para aceptar solo números. No mostrará ningún mensaje, pero evitará que ingreses incorrectamente. A mí me funcionó, el usuario no pudo ingresar nada excepto el número.

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


2

Lo manejaría en el evento KeyDown.

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

2
¿Qué pasa con las teclas como "Retroceso", "Eliminar", "Flecha-Tecla-Izquierda", "Flecha-Tecla-Derecha", Copiar y Pegar, Dígitos ingresados ​​por Numpad (se intercambian como! Dígitos)
usuario799821

Simplemente agregue algunas pruebas más como esta: 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;
        }
    }
}

prueba esto es muy simple


2

Eche un vistazo al manejo de entrada en WinForm

He publicado mi solución que utiliza los eventos ProcessCmdKey y OnKeyPress en el cuadro de texto. Los comentarios le muestran cómo usar una expresión regular para verificar la pulsación de teclas y bloquear / permitir adecuadamente.


2

Hola, puedes hacer algo como esto en el evento de cambio de texto del cuadro de texto.

aquí hay una demostración

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

Gracias, es muy útil.
Kiran RS

2

Parece que muchas de las respuestas actuales a esta pregunta analizan manualmente el texto de entrada. Si está buscando un tipo numérico incorporado específico (p. Ej. intO double), ¿por qué no simplemente delegar el trabajo al TryParsemétodo de ese tipo ? Por ejemplo:

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

Si quieres algo más genérico pero compatible con el diseñador de 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;
        }
    }
}

Y finalmente, si quieres algo completamente genérico y no te importa el soporte de 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

Se deben aceptar números enteros y flotantes, incluidos los números negativos.

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

Este es mi enfoque:

  1. usando linq (filtro fácil de modificar)
  2. copiar / pegar código de prueba
  3. mantiene la posición de intercalación cuando presiona un carácter prohibido
  4. acepta ceros a la izquierda
  5. y cualquier número de tamaño

    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

Usando el enfoque descrito en la respuesta de Fabio Iotti, he creado una solución más genérica:

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", que contiene todo el comportamiento de validación no trivial. Todo lo que queda por hacer es heredar de esta clase y anular el método "IsValid" con cualquier lógica de validación requerida. Por ejemplo, usando esta clase, es posible crear "RegexedTextBox" que aceptará solo cadenas que coincidan con expresiones regulares específicas:

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

Después de eso, heredando de la clase "RegexedTextBox", podemos crear fácilmente los controles "PositiveNumberTextBox" y "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

Lamento despertar a los muertos, pero pensé que alguien podría encontrar esto útil para referencia futura.

Así es como lo manejo. Maneja números de coma flotante, pero puede modificarse fácilmente para enteros.

Básicamente solo puede presionar 0 - 9 y .

Solo puede tener un 0 antes del .

Todos los demás caracteres se ignoran y se mantiene la posición del cursor.

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

Aquí hay una versión int rápidamente modificada:

    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
Esta solución es reinventar la rueda con advertencias. Localización por ejemplo.
Julien Guertault

1

Este funciona con copiar y pegar, arrastrar y soltar, presionar tecla, evita el desbordamiento y es bastante simple

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

No olvide que un usuario puede pegar un texto no válido en un TextBox.

Si desea restringir eso, siga el siguiente código:

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

También estaba buscando la mejor manera de verificar solo los números en el cuadro de texto y el problema con la pulsación de teclas es que no admite copiar y pegar haciendo clic con el botón derecho o en el portapapeles, así que se me ocurrió este código que valida el cursor cuando sale del campo de texto y también busca campo vacío. (versión adaptada de 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 parece una muy mala elección para un evento.
LarsTech

@LarsTech, lo que pensé que había cambiado de texto, incluso puede causar un cuadro de mensaje de error antes, incluso si el usuario se da cuenta del error e intenta solucionarlo, así que pensé que funcionaría mejor. ¿Cuál crees que es el mejor evento para este caso?
Alston Antony

Comentario tardío de @AlstonAntony, lo sé. Pero un simple evento de clic que se activa al hacer clic derecho no sería suficiente
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 solución

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) otra solución de 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;
    }
}

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

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


0

Al hacer clic en el botón, puede verificar el texto del cuadro de texto por bucle:

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

Respuesta más simple:

_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());
};
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.