Como faço para criar uma caixa de texto que aceite apenas números?

583

Eu tenho um aplicativo de formulários do Windows com um controle de caixa de texto que eu quero aceitar apenas valores inteiros. No passado, eu fiz esse tipo de validação sobrecarregando o evento KeyPress e apenas removendo caracteres que não se encaixavam na especificação. Eu olhei para o controle MaskedTextBox, mas gostaria de uma solução mais geral que pudesse funcionar talvez com uma expressão regular ou depender dos valores de outros controles.

Idealmente, isso se comportaria de tal maneira que pressionar um caractere não numérico não produziria resultado ou forneceria imediatamente ao usuário feedback sobre o caractere inválido.

Mykroft
fonte
11
números ou dígitos? grande diferença: mesmo inteiros podem ir negativo
Joel Coehoorn
8
A pergunta era destinada a números, incluindo todo o conjunto de números racionais.
7779 Mykroft

Respostas:

797

Duas opções:

  1. Use um em NumericUpDownvez disso. NumericUpDown faz a filtragem para você, o que é legal. É claro que também oferece aos usuários a capacidade de pressionar as setas para cima e para baixo no teclado para aumentar e diminuir o valor atual.

  2. Manipule os eventos de teclado apropriados para impedir qualquer coisa, menos a entrada numérica. Eu tive sucesso com esses dois manipuladores de eventos em um TextBox padrão:

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

Você pode remover a verificação '.'(e a verificação subsequente de mais de uma '.') se o seu TextBox não permitir casas decimais. Você também pode adicionar uma verificação para ver '-'se o seu TextBox deve permitir valores negativos.

Se você deseja limitar o usuário ao número de dígitos, use: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits

Matt Hamilton
fonte
5
A única desvantagem do NumericUpDown é que ele não fornece feedback quando você insere um valor fora dos valores máximos ou mínimos permitidos - apenas altera o que você digitou. Um TextBox pode pelo menos permitir valores inválidos para que você possa avisar o usuário quando ele enviar o formulário.
Matt Hamilton
7
Isso é verdade - o usuário sempre pode colar alguns caracteres não numéricos. Você esperaria que a validação do formulário entendesse isso, já que em algum momento você desejará fazer um Int32.TryParse ou algo assim.
Matt Hamilton
52
Você precisará de algum esforço adicional para globalizar isso, substituindo as verificações por '.' com verificações em CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
10119 Jeff Yates
6
@HamishGrubijan, IsControl não tem nada a ver com a tecla Control; retorna se um caractere é ou não um controle. Ao permitir que os caracteres de controle, você não quebrar as coisas como backspace, exclusão ou as teclas de seta
Thomas Levesque
13
Isso ainda aceita entrada ctrl + v ilegal, a propósito; um bug que ainda existe no controle oficial NumericUpDown.
Nyerguds
149

E só porque é sempre mais divertido fazer coisas em uma linha ...

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

NOTA: Isso NÃO impede que um usuário copie / cole nesta caixa de texto. Não é uma maneira segura de limpar seus dados.

BFree
fonte
Esta não é uma solução geral, pois funciona apenas para intergers. Eu tive que implementar isso recentemente e acabei com a tentativa de analisar a sequência resultante em número e permitir a entrada apenas se a análise tiver sido bem
#
1
Isso pode não funcionar quando vários métodos manipulam KeyPresseventos da mesma caixa de texto. Um evento pode ser definido e.Handledcomo true e outro pode ser definido como false. Em geral, é melhor usar #if (...) e.Handled = true;
Nathaniel Jones
2
Você pode desativar a propriedade ShortcutsEnabled para impedir a colagem de cópias pelo teclado ou menu
Ahmad
3
HAHA! Sim! Um forros!
21315 Jamie L.
3
Eh. Um TextChangedevento que vai sobre ele com um regex pode corrigir copiar e colar;)
Nyerguds
51

Estou partindo do contexto e das tags que você usou para escrever um aplicativo .NET C #. Nesse caso, você pode assinar o evento alterado de texto e validar cada toque 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);
    }
}
Anthony D
fonte
22
Isso não vai dar um efeito muito estranho se você digitar no meio de um número?
Colin Pickard
5
e também deve ser:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
Pieniadz
3
E se o primeiro personagem em si não é um dígito ... não iria subtrair 1, nesse caso, lançar um erro ....
manu_dilip_shah
6
Além disso, o uso de TextChanged em vez de KeyPress cria um pouco de recursão, pois o código salta para um segundo evento TextChanged após o método Remove.
WEFX
2
Você alterou os parâmetros de entrada e padrão para sua função IsMatch. A entrada deve ser a primeira, depois o padrão. msdn.microsoft.com/pt-br/library/sdx2bds0(v=vs.110).aspx
Mibou
36

Aqui está um controle personalizado simples do Winforms, derivado do TextBox padrão, que permite apenas a entrada System.Int32 (pode ser facilmente adaptado para outros tipos, como System.Int64, etc.). Ele suporta operações de copiar / colar e 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);
    }

Atualização 2017 : Minha primeira resposta tem alguns problemas:

  • você pode digitar algo maior que o número inteiro de um determinado tipo (por exemplo, 2147483648 é maior que Int32.MaxValue);
  • de maneira geral, não há validação real do resultado do que foi digitado;
  • ele lida apenas com int32, você precisará escrever um controle derivado específico de TextBox para cada tipo (Int64, etc.)

Então, eu vim com outra versão mais genérica, que ainda suporta copiar / colar, + e - assinar, 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 o Int32, você pode derivar dele, assim:

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

ou sem derivação, use o novo evento TextValidating como este:

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

mas o que é legal é que funciona com qualquer string e qualquer rotina de validação.

Simon Mourier
fonte
Isso é ótimo, agradável e simples, facilmente usado e lida com tentativas incomuns de entrada. Obrigado!
WiredEarp 28/09
1
Nota sobre a versão 2017, quando há um valor, por exemplo, 1 e você acertar backspace é ignorado enquanto se você tivesse dizer 120 e backspace hit três vezes ficamos com 1.
Karen Payne
1
Sua ValidatingTextbox é de longe a melhor implementação que já vi há algum tempo. Simples e eficaz. Obrigado!
Samuel
19

É exatamente para isso que os eventos Validados / Validados foram projetados.

Aqui está o artigo do MSDN sobre o tópico: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

A versão TL; DR: verifique a propriedade .Text no evento Validating e configure e.Cancel=True quando os dados são inválidos.

Quando você define e.Cancel = True, o usuário não pode sair do campo, mas você precisará fornecer algum tipo de feedback de que algo está errado. Altero a cor de fundo da caixa para vermelho claro para indicar um problema. Certifique-se de configurá-lo novamente SystemColors.Windowquando a validação for chamada com um bom valor.

TomXP411
fonte
1
+1 por mencionar uma abordagem muito idiomática da API. Eu sou relativamente novo no Windows Forms, e é uma variedade de funcionalidades e documentos do MSDN, então também obrigado pelo ponteiro de documento específico para Validating. <nitpick>O OP menciona que desabilitar / indicar imediatamente um caracter inválido é ideal, mas Validatingparece exigir que o foco seja movido para outra forma / controle antes que ele entre em vigor. </nitpick>Ainda assim, essa é uma ótima abordagem e sempre vale a pena considerar no caso mais geral.
William William
13

Experimente um MaskedTextBox . É necessário um formato de máscara simples para que você possa limitar a entrada a números ou datas ou qualquer outra coisa.

Andrew Kennan
fonte
2
Especificamente, não quero usar um MaskedTextBox. Os formatos que eles permitem podem ser muito limitantes. Eles trabalham para este caso, mas eu gostaria de fazer algo mais geral.
Mykroft 20/01/2009
12

Você pode usar o 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();
    }
}
Davit Tvildiani
fonte
Parece que deve funcionar bem se você usou Undo(), mas resulta em um StackOverflowException.
Drew Chapin
Parece que a propriedade TextChanged faz parte da rotina que você deseja desfazer (). Eu tenho variável para toda a janela e estou usando public int txtBoxValue, e se o tryParse não funcionar, eu reverto o texto no txtBox portxtBox.Text = txtBoxValue.ToString();
L. Zeda
8

Isso pode ser útil. Permite valores numéricos "reais", incluindo pontos decimais adequados e sinais de mais ou menos anteriores. Chame de dentro do 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;
    }
Roger Garrett
fonte
6

Eu tenho trabalhado em uma coleção de componentes para concluir as coisas ausentes no WinForms, aqui está: Formulários avançados

Em particular, esta é a classe para um 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);
    }
}

Basta adicionar algo como myNumbericTextBox.RegexString = "^(\\d+|)$";deve ser suficiente.

Fabio Iotti
fonte
5

Basta usar um NumericUpDowncontrole e definir a visibilidade desses botões feios para baixo false.

numericUpDown1.Controls[0].Visible = false;

NumericUpDown é, na verdade, uma coleção de controles que contêm uma 'caixa giratória' (botões para cima e para baixo), uma caixa de texto e algum código para validar e agrupar tudo.

Marcação:

YourNumericUpDown.Controls[0].visible = false 

ocultará os botões enquanto mantém o código subjacente ativo.

Embora não seja uma solução óbvia, é simples e eficaz. .Controls[1]ocultaria a parte da caixa de texto se você quisesse fazer isso.

user2163234
fonte
A resposta aceita não incluiu nenhuma informação sobre como remover os botões para cima e para baixo, como fazer isso não é óbvio, pois não há interfaces legíveis por humanos para habilitá-las ou desabilitá-las. NumericUpDown é, na verdade, uma coleção de controles contendo uma caixa de texto e uma "caixa de rotação" (botões para cima e para baixo) e algum código que trata da validação de entrada.
user2163234
4

Eu fiz algo para isso no CodePlex .

Funciona interceptando o evento TextChanged. Se o resultado for um bom número, ele será armazenado. Se houver algo errado, o último bom valor será restaurado. A fonte é um pouco grande demais para ser publicada aqui, mas aqui está um link para a classe que lida com o núcleo dessa lógica.

GvS
fonte
4

basta usar este código na caixa de texto:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

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

Em nossa página da Web com a definição de caixa de texto, podemos adicionar um onkeypressevento para aceitar apenas números. Não mostrará nenhuma mensagem, mas impedirá a entrada incorreta. Funcionou para mim, o usuário não pôde digitar nada, exceto o número.

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

você pode usar o evento TextChanged / Keypress, usar uma regex para filtrar números e executar alguma ação.

Perpetualcoder
fonte
2

Eu lidaria com isso no evento KeyDown.

void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            char c = Convert.ToChar(e.PlatformKeyCode);
            if (!char.IsDigit(c))
            {
                e.Handled = true;
            }
        }
Shaz
fonte
2
E sobre Chaves como "Backspace", "Delete", "Arrow-Key-esquerda", "Arrow-Key-direita", copiar e colar, dígitos inseridos pelo teclado numérico (eles são negociadas sob dígitos!)
user799821
Basta adicionar mais alguns testes como este: if (! Char.IsDigit (c) && c! = (Char) Keys.Back)) #
11447 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;
        }
    }
}

tente isso é muito simples

rithish
fonte
2

Dê uma olhada no tratamento de entrada no WinForm

Publiquei minha solução que usa os eventos ProcessCmdKey e OnKeyPress na caixa de texto. Os comentários mostram como usar um Regex para verificar o pressionamento de tecla e bloquear / permitir adequadamente.

benPearce
fonte
2

Oi, você pode fazer algo assim no evento de alteração de texto da caixa de texto.

aqui está uma demonstração

    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;
    }
Chandan Kumar
fonte
Obrigado, é muito útil.
Kiran RS
2

Parece que muitas das respostas atuais para esta pergunta estão analisando manualmente o texto de entrada. Se você está procurando um tipo numérico interno específico (por exemplo, intou double), por que não delegar o trabalho ao TryParsemétodo desse tipo ? Por exemplo:

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 você deseja algo mais genérico, mas ainda compatível com o Designer do 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, finalmente, se você deseja algo totalmente genérico e não se importa com o suporte do 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;
        }
    }
}
William
fonte
2

É necessário aceitar números inteiros e flutuantes, incluindo os 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));
}
nabeghe
fonte
2

Esta é a minha abordagem:

  1. usando linq (fácil de modificar o filtro)
  2. copiar / colar código de prova
  3. mantém a posição de cursor quando você pressiona um caractere proibido
  4. aceita zeros esquerdos
  5. e qualquer número de tamanho

    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;
        }
    }
Ing. Gerardo Sánchez
fonte
2

Usando a abordagem descrita na resposta de Fabio Iotti, criei uma solução mais 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 contém todo o comportamento de validação não trivial. Tudo o que resta a fazer é herdar dessa classe e substituir o método "IsValid" por qualquer lógica de validação necessária. Por exemplo, usando esta classe, é possível criar "RegexedTextBox", que aceitará apenas cadeias que correspondam a expressões 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);
    }
}

Depois disso, herdando da classe "RegexedTextBox", podemos criar facilmente os controles "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*$") { }
}
Urso polar
fonte
1

Desculpe acordar os mortos, mas achei que alguém poderia achar isso útil para referência futura.

Aqui está como eu lido com isso. Ele lida com números de ponto flutuante, mas pode ser facilmente modificado para números inteiros.

Basicamente, você pode pressionar apenas 0 - 9 e .

Você pode ter apenas um 0 antes do .

Todos os outros caracteres são ignorados e a posição do cursor é mantida.

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

Aqui está uma versão int rapidamente 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;
    }
jardinagem
fonte
2
Esta solução está reinventando a roda com ressalvas. Localização, por exemplo.
Julien Guertault
1

Este funciona com copiar e colar, arrastar e soltar, tecla pressionada, evita o estouro e é bastante simples

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);
        }
    }       
}
user1626874
fonte
1

Não esqueça que um usuário pode colar um texto inválido em um arquivo TextBox.

Se você deseja restringir isso, siga o código abaixo:

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;
}   
Divya
fonte
1

Eu também estava procurando a melhor maneira de verificar apenas números na caixa de texto e o problema com o pressionamento de tecla foi que ele não suporta copiar e colar com o botão direito ou a área de transferência, então surgiu esse código que valida quando o cursor sai do campo de texto e também procura por campo vazio. (versão adaptada do 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();
    }
}
Alston Antony
fonte
MouseLeave parece ser uma péssima escolha para um evento.
LarsTech
O @LarsTech, o que pensei ter sido alterado de texto, pode causar mensagens de erro antes mesmo que o usuário perceba o erro e tente corrigi-lo, então pensei em trabalhar melhor. Qual você acha que é o melhor evento para este caso?
Alston Antony
@AlstonAntony comentário tardio, eu sei. Mas um simples evento de clique que é ativado com o botão direito seria suficiente, não?
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);
}
cara novo
fonte
0

3 solução

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) uma outra solução do 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) usando o MaskedTextBox: http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx

menina modesta e fofa
fonte
0

Ao clicar no botão, você pode verificar o texto da caixa de texto por for loop:

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
    }
Shaahin
fonte
0

Resposta mais simples:

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