Question Comment créer une zone de texte n'acceptant que des nombres?


J'ai une application Windows Forms avec un contrôle de zone de texte que je veux n'accepter que des valeurs entières. Dans le passé, j'ai effectué ce type de validation en surchargeant l'événement KeyPress et en supprimant simplement les caractères qui ne correspondaient pas aux spécifications. J'ai examiné le contrôle MaskedTextBox, mais j'aimerais une solution plus générale qui pourrait fonctionner avec une expression régulière, ou dépendre des valeurs des autres contrôles.

Dans l'idéal, cela fonctionnerait de telle sorte que le fait d'appuyer sur un caractère non numérique ne produirait aucun résultat ou fournirait immédiatement à l'utilisateur des commentaires sur le caractère non valide.


485
2018-01-20 21:55


origine


Réponses:


Deux options:

  1. Utiliser un NumericUpDown au lieu. NumericUpDown fait le filtrage pour vous, ce qui est bien. Bien sûr, cela donne à vos utilisateurs la possibilité d’appuyer sur les flèches haut et bas du clavier pour incrémenter et décrémenter la valeur actuelle.

  2. Manipulez les événements de clavier appropriés pour empêcher tout élément autre que la saisie numérique. J'ai eu du succès avec ces deux gestionnaires d'événements sur une 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;
        }
    }
    

Vous pouvez supprimer le chèque pour '.' (et le contrôle subséquent pour plus d'un '.') si votre TextBox ne doit pas autoriser les décimales. Vous pouvez également ajouter un chèque pour '-' si votre TextBox doit autoriser des valeurs négatives.

Si vous souhaitez limiter l'utilisateur pour le nombre de chiffres, utilisez: textBox1.MaxLength = 2; // this will allow the user to enter only 2 digits


667
2018-01-20 22:04



Et juste parce que c'est toujours plus amusant de faire des choses en une seule ligne ...

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

REMARQUE: cela n'empêche PAS un utilisateur de copier / coller dans cette zone de texte. Ce n'est pas un moyen sûr de nettoyer vos données.


118
2018-01-20 22:24



Je suppose du contexte et les étiquettes que vous avez utilisées que vous écrivez une application .NET C #. Dans ce cas, vous pouvez vous abonner à l'événement text changed et valider chaque coup de clé.

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

43
2018-01-20 22:02



Voici un simple contrôle personnalisé Winforms, dérivé du TextBox standard, qui ne permet que l'entrée System.Int32 (il pourrait être facilement adapté à d'autres types tels que System.Int64, etc.). Il supporte les opérations de copier / coller et les nombres négatifs:

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

Mise à jour 2017: Ma première réponse a quelques défauts:

  • vous pouvez taper quelque chose de plus long qu'un entier d'un type donné (par exemple, 2147483648 est supérieur à Int32.MaxValue);
  • plus généralement, il n'y a pas de réelle validation du résultat de ce qui a été typé;
  • il ne gère que int32, vous devrez écrire un contrôle spécifique dérivé de TextBox pour chaque type (Int64, etc.)

Donc, je suis venu avec une autre version qui est plus générique, qui supporte toujours copier / coller, + et - signer, 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; }
}

Pour Int32, vous pouvez en dériver, comme ceci:

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

ou sans dérivation, utilisez le nouvel événement TextValidating comme ceci:

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

mais ce qui est bien c'est que cela fonctionne avec n'importe quelle chaîne et n'importe quelle routine de validation.


29
2017-09-11 16:23



C'est exactement pour quoi les événements validés / validés ont été conçus.

Voici l'article MSDN sur le sujet: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating.aspx

TL: DR version: vérifiez la propriété .Text dans l'événement Validating et définissez e.Cancel=Truelorsque les données sont invalides

Lorsque vous définissez e.Cancel = True, l'utilisateur ne peut pas quitter le champ, mais vous devez lui donner une sorte de commentaire indiquant que quelque chose ne va pas. Je change la couleur de fond de la boîte en rouge clair pour indiquer un problème. Assurez-vous de le remettre à SystemColors.Window lorsque la validation est appelée avec une bonne valeur.


17
2017-07-27 00:40



Essayez un MaskedTextBox. Il prend un format de masque simple afin que vous puissiez limiter l'entrée aux nombres ou aux dates ou autres.


13
2018-01-20 22:01



Vous pouvez utiliser le TextChanged un événement

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

11
2018-03-31 19:55