Comment créer une zone de texte qui n'accepte que des chiffres?

583

J'ai une application Windows Forms avec un contrôle de zone de texte que je souhaite accepter uniquement des valeurs entières. Dans le passé, j'ai fait 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 regardé le contrôle MaskedTextBox mais j'aimerais une solution plus générale qui pourrait fonctionner avec peut-être une expression régulière, ou dépendre des valeurs d'autres contrôles.

Idéalement, cela se comporterait de telle sorte que la pression d'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.

Mykroft
la source
11
des chiffres ou des chiffres? grande différence: même les nombres entiers peuvent devenir négatifs
Joel Coehoorn
8
La question était destinée aux nombres comprenant l'ensemble entier des nombres rationnels.
Mykroft

Réponses:

797

Deux options:

  1. Utilisez NumericUpDownplutôt un . NumericUpDown fait le filtrage pour vous, ce qui est bien. Bien sûr, cela donne également à vos utilisateurs la possibilité d'appuyer sur les flèches haut et bas du clavier pour augmenter et diminuer la valeur actuelle.

  2. Gérez les événements de clavier appropriés pour empêcher autre chose 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 la vérification '.'(et la vérification ultérieure de plusieurs '.') si votre TextBox ne doit pas autoriser les décimales. Vous pouvez également ajouter une vérification pour savoir '-'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

Matt Hamilton
la source
5
Le seul inconvénient de NumericUpDown est qu'il ne fournit aucun retour lorsque vous entrez une valeur en dehors des valeurs maximales ou minimales autorisées - il modifie simplement ce que vous avez tapé. Un TextBox peut au moins autoriser des valeurs non valides afin que vous puissiez avertir l'utilisateur lorsqu'il soumet le formulaire.
Matt Hamilton
7
C'est vrai - l'utilisateur peut toujours coller certains caractères non numériques. Vous pouvez espérer que la validation du formulaire interceptera cela, car à un moment donné, vous voudrez faire un Int32.TryParse ou quelque chose.
Matt Hamilton
52
Vous aurez besoin d'un effort supplémentaire pour globaliser cela en remplaçant les chèques pour "." avec des vérifications sur CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator.
Jeff Yates
6
@HamishGrubijan, IsControl n'a rien à voir avec la touche Contrôle; il renvoie si un caractère est un caractère de contrôle ou non. En autorisant les caractères de contrôle, vous ne cassez pas des choses comme le retour arrière, la suppression ou les touches fléchées
Thomas Levesque
13
Soit dit en passant, cela accepte toujours les entrées ctrl + v illégales; un bogue qui existe même dans le contrôle NumericUpDown officiel.
Nyerguds
149

Et juste parce qu'il 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 désinfecter vos données.

BFree
la source
ce n'est pas une solution générale car cela ne fonctionne que pour les intergers. J'ai dû implémenter une telle chose récemment et j'ai fini par essayer d'analyser la chaîne résultante en nombre et d'autoriser l'entrée uniquement si l'analyse a réussi
grzegorz_p
1
Cela peut ne pas fonctionner lorsque plusieurs méthodes gèrent les KeyPressévénements de la même zone de texte. Un événement peut être défini e.Handledsur true, puis un autre peut le définir sur false. En général, il vaut mieux utiliserif (...) e.Handled = true;
Nathaniel Jones
2
Vous pouvez désactiver la propriété ShortcutsEnabled pour empêcher le copier-coller par le clavier ou le menu
Ahmad
3
HAHA! Oui! Un paquebot!
Jamie L.
3
Eh. Un TextChangedévénement qui le dépasse avec une expression régulière peut corriger le copier-coller;)
Nyerguds
51

Je suppose à partir du contexte et des balises que vous avez utilisées que vous écrivez une application .NET C #. Dans ce cas, vous pouvez vous abonner à l'événement de modification de texte et valider chaque coup de touche.

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
la source
22
Cela ne donnera-t-il pas un effet très étrange si vous tapez au milieu d'un nombre?
Colin Pickard du
5
et aussi ça devrait être:textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
Pieniadz
3
que faire si le premier caractère lui-même n'est pas un chiffre ... ne soustrait pas 1 dans ce cas jette une erreur ....
manu_dilip_shah
6
En outre, l'utilisation de TextChanged au lieu de KeyPress crée un peu de récursivité dans le sens où le code sautera dans un deuxième événement TextChanged après la méthode Remove.
WEFX
2
Vous avez changé les paramètres d'entrée et de modèle pour votre fonction IsMatch. L'entrée doit être d'abord, puis le modèle. msdn.microsoft.com/en-us/library/sdx2bds0(v=vs.110).aspx
Mibou
36

Voici un simple contrôle personnalisé Winforms autonome, dérivé de la TextBox standard, qui autorise uniquement l'entrée System.Int32 (il pourrait être facilement adapté pour d'autres types tels que System.Int64, etc.). Il prend en charge 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 problèmes:

  • vous pouvez taper quelque chose qui est 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 véritable validation du résultat de ce qui a été tapé;
  • il ne gère que l'int32, vous devrez écrire un contrôle dérivé TextBox spécifique pour chaque type (Int64, etc.)

J'ai donc proposé une autre version plus générique, qui prend toujours en charge le copier / coller, les signes + et -, 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 toute routine de validation.

Simon Mourier
la source
C'est génial, agréable et simple, facile à utiliser et traite des tentatives de saisie inhabituelles. Merci!
WiredEarp
1
Remarque sur la version 2017, quand il y a une valeur, par exemple 1 et que vous appuyez sur la touche de retour arrière, elle est ignorée alors que si vous aviez dit 120 et frappé la touche arrière trois fois, nous nous retrouvons avec 1.
Karen Payne
1
Votre ValidatingTextbox est de loin la meilleure implémentation que j'ai vue depuis un moment. Simple et efficace. Merci!
Samuel
19

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

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

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

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

TomXP411
la source
1
+1 pour avoir mentionné une approche très idiomatique de l'API. Je suis relativement nouveau dans Windows Forms, et c'est une jungle de fonctionnalités et de documents MSDN, donc merci aussi pour le pointeur de document spécifique vers Validating. <nitpick>L'OP mentionne qu'interdire / indiquer immédiatement un caractère invalidant est idéal, mais Validatingsemble exiger que le focus soit déplacé vers un autre formulaire / contrôle avant qu'il ne prenne effet. </nitpick>Pourtant, c'est une excellente approche et mérite toujours d'être considérée dans le cas plus général.
William
13

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

Andrew Kennan
la source
2
Je ne veux pas spécifiquement utiliser un MaskedTextBox. Les formats qu'ils autorisent peuvent être très limitatifs. Ils travaillent pour ce cas, mais j'aimerais faire quelque chose de plus général.
Mykroft
12

Vous pouvez utiliser l' TextChangedé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();
    }
}
Davit Tvildiani
la source
Il semble que cela devrait bien fonctionner si vous l'avez utilisé Undo(), mais il en résulte un StackOverflowException.
Drew Chapin
Il semble que la propriété TextChanged fasse partie de la routine que vous souhaitez annuler (). J'ai une variable pour toute la fenêtre et j'utilise public int txtBoxValue, et si tryParse ne fonctionne pas, je rétablis le texte dans txtBox partxtBox.Text = txtBoxValue.ToString();
L. Zeda
8

Cela pourrait être utile. Il permet des valeurs numériques "réelles", y compris les décimales appropriées et les signes plus ou moins précédents. Appelez-le depuis l'événement KeyPress associé.

       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
la source
6

J'ai travaillé sur une collection de composants pour compléter les éléments manquants dans WinForms, le voici: Formulaires avancés

En particulier, c'est la classe d'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);
    }
}

Ajouter simplement quelque chose comme ça myNumbericTextBox.RegexString = "^(\\d+|)$";devrait suffire.

Fabio Iotti
la source
5

Utilisez simplement une NumericUpDowncommande et définissez la laideur de la visibilité des boutons false.

numericUpDown1.Controls[0].Visible = false;

NumericUpDown est en fait une collection de contrôles contenant une «zone de sélection numérique» (boutons haut / bas), une zone de texte et du code pour valider et balancer tout cela ensemble.

Marquage:

YourNumericUpDown.Controls[0].visible = false 

masquera les boutons tout en gardant le code sous-jacent actif.

Sans être une solution évidente, elle est simple et efficace. .Controls[1]masquerait la partie de la zone de texte si vous vouliez le faire à la place.

user2163234
la source
La réponse acceptée ne contenait aucune information sur la façon de supprimer les boutons haut / bas, comment le faire n'est pas évident car il n'y a pas d'interfaces lisibles par l'homme pour les activer ou les désactiver. NumericUpDown est en fait une collection de contrôles contenant une zone de texte et une "zone de sélection numérique" (boutons haut / bas) et une certaine validation de saisie de code.
user2163234
4

J'ai fait quelque chose pour cela sur CodePlex .

Il fonctionne en interceptant l'événement TextChanged. Si le résultat est un bon nombre, il sera enregistré. Si quelque chose ne va pas, la dernière bonne valeur sera restaurée. La source est un peu trop volumineuse pour être publiée ici, mais voici un lien vers la classe qui gère le cœur de cette logique.

GvS
la source
4

utilisez simplement ce code dans la zone de texte:

private void textBox1_TextChanged(object sender, EventArgs e)
{

    double parsedValue;

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

Dans notre page Web avec la définition de zone de texte, nous pouvons ajouter un onkeypressévénement pour accepter uniquement les numéros. Il ne montrera aucun message mais il vous évitera une mauvaise saisie. Cela a fonctionné pour moi, l'utilisateur ne pouvait rien saisir sauf le numéro.

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

vous pouvez utiliser l' événement TextChanged / Keypress, utiliser une expression régulière pour filtrer les nombres et prendre des mesures.

Perpetualcoder
la source
2

Je le gérerais dans l'événement KeyDown.

void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            char c = Convert.ToChar(e.PlatformKeyCode);
            if (!char.IsDigit(c))
            {
                e.Handled = true;
            }
        }
Shaz
la source
2
Qu'en est-il des touches comme "Backspace", "Delete", "Arrow-Key-Left", "Arrow-Key-Right", Copy and Paste, Digits entré par Numpad (ils sont échangés en tant que!
Digit
Ajoutez simplement quelques tests comme celui-ci: 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;
        }
    }
}

essayez c'est très simple

rithish
la source
2

Jeter un coup d'œil à gestion des entrées dans WinForm

J'ai publié ma solution qui utilise les événements ProcessCmdKey et OnKeyPress sur la zone de texte. Les commentaires vous montrent comment utiliser une Regex pour vérifier la pression de touche et bloquer / autoriser de manière appropriée.

benPearce
la source
2

Salut, vous pouvez faire quelque chose comme ça dans l'événement textchanged de la zone de texte.

voici une démo

    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
la source
Merci, c'est très utile.
Kiran RS
2

Il semble que la plupart des réponses actuelles à cette question analysent manuellement le texte saisi. Si vous recherchez un type numérique intégré spécifique (par exemple intou double), pourquoi ne pas simplement déléguer le travail à la TryParseméthode de ce type ? Par exemple:

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 vous voulez quelque chose de plus générique mais toujours compatible avec Visual Studio's Designer:

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

Et enfin, si vous voulez quelque chose de complètement générique et que vous ne vous souciez pas du support 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;
        }
    }
}
William
la source
2

Les nombres entiers et flottants doivent être acceptés, y compris les nombres négatifs.

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
la source
2

Voici mon approche:

  1. en utilisant linq (filtre facile à modifier)
  2. copier / coller du code de preuve
  3. conserve la position du curseur lorsque vous appuyez sur un caractère interdit
  4. accepte les zéros laissés
  5. et tous les numéros de taille

    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
la source
2

En utilisant l'approche décrite dans la réponse de Fabio Iotti, j'ai créé une solution plus générique:

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", qui contient tous les comportements de validation non triviaux. Il ne reste plus qu'à hériter de cette classe et remplacer la méthode "IsValid" avec la logique de validation requise. Par exemple, en utilisant cette classe, il est possible de créer "RegexedTextBox" qui n'acceptera que les chaînes qui correspondent à une expression régulière spécifique:

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

Après cela, héritant de la classe "RegexedTextBox", nous pouvons facilement créer des contrôles "PositiveNumberTextBox" et "PositiveFloatingPointNumberTextBox":

public sealed class PositiveNumberTextBox : RegexedTextBox {
    public PositiveNumberTextBox() : base(@"^\d*$") { }
}

public sealed class PositiveFloatingPointNumberTextBox : RegexedTextBox {
    public PositiveFloatingPointNumberTextBox()
        : base(@"^(\d+\" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator + @")?\d*$") { }
}
Ours polaire
la source
1

Désolé de réveiller les morts, mais j'ai pensé que quelqu'un pourrait trouver cela utile pour référence future.

Voici comment je le gère. Il gère les nombres à virgule flottante, mais peut facilement être modifié pour les nombres entiers.

Fondamentalement, vous ne pouvez appuyer que sur 0 - 9 et .

Vous ne pouvez avoir qu'un seul 0 avant le .

Tous les autres caractères sont ignorés et la position du curseur est conservée.

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

Voici une version int rapidement modifiée:

    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;
    }
yardape
la source
2
Cette solution réinvente la roue avec des mises en garde. Localisation par exemple.
Julien Guertault
1

Celui-ci fonctionne avec le copier-coller, le glisser-déposer, la touche enfoncée, empêche le débordement et est assez 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);
        }
    }       
}
user1626874
la source
1

N'oubliez pas qu'un utilisateur peut coller un texte invalide dans un fichier TextBox.

Si vous souhaitez restreindre cela, suivez le code ci-dessous:

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
la source
1

Je cherchais également la meilleure façon de vérifier uniquement les nombres dans la zone de texte et le problème avec la pression de touche était qu'il ne prend pas en charge le copier-coller par un clic droit ou un presse-papiers.J'ai donc trouvé ce code qui valide le moment où le curseur quitte le champ de texte et vérifie également champ vide. (version adaptée 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();
    }
}
Alston Antony
la source
MouseLeave semble être un très mauvais choix pour un événement à utiliser.
LarsTech du
@LarsTech ce que je pensais avoir été textotransformé peut même provoquer une boîte de message d'erreur avant même si l'utilisateur se rend compte de l'erreur et essaie de la corriger, donc je pensais que je travaillerais mieux. Selon vous, quel est le meilleur événement pour cette affaire?
Alston Antony du
@AlstonAntony commentaire tardif, je sais. Mais un simple événement de clic qui s'active sur le clic droit suffirait-il?
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);
}
nouveau gars
la source
0

3 solution

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) une autre solution 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;
    }
}

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

3) à l'aide de MaskedTextBox: http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.aspx

fille modeste et mignonne
la source
0

En cliquant sur le bouton, vous pouvez vérifier le texte de la zone de texte par pour la boucle:

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
la source
0

Réponse plus 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());
};
micahhoover
la source