Click here to Skip to main content
15,861,125 members
Articles / Desktop Programming / Windows Forms
Article

Simple Numeric TextBox

Rate me:
Please Sign up or sign in to vote.
4.69/5 (29 votes)
9 Nov 2008CPOL3 min read 132.5K   5.8K   65   27
A WinForms TextBox that only accepts digits.

Overview

This is a simple extension/restriction of the System.Windows.Forms.TextBox component. Only digits can be entered into the control. Pasting is also checked, and if the text contains other characters, then it is cancelled. I found many examples on various websites, but none that I found were suitable for my purpose. Either they allowed or enforced things I didn't want (see 'What I haven't done' below), or they didn't completely handle all the standard keyboard and mouse functions (see 'Surely this is simple' below), for example, allowing the Home key or Shift+End etc.

Language

The source code is in C#, .NET 2.0, VS2008. I've included the compiled DLL so VB users can use this control.

What I haven't done

I haven't added any range or bounds control - it's a text box, not an int/double/decimal... box. There is no support for number separators, currency symbols, or even the - sign. They weren't required for the implementation I needed. If you want to add them, it shouldn't be too difficult.

Surely this is simple, you just...

That's what I thought too, until about two minutes into coding this! There's actually quite a lot that we do all the time with the text box, but never give it a second thought. As well as digits, we need to allow edit key combinations and navigation/selection keys and combinations. Pasting can be done either by keyboard or by mouse actions, so handling key events for this isn't sufficient.

The code

The interesting parts of the code are in the overridden OnKeyDown and the private CheckPasteValid methods.

OnKeyDown

I've simply built bools for numeric, edit, and navigation keys so I can test one value for each group. Ctrl+A sometimes needs separate handling, so I created one for that too.

C#
protected override void OnKeyDown(KeyEventArgs e)
{
    bool result = true;

    bool numericKeys = (
        ((e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) ||
        (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9))
        && e.Modifiers != Keys.Shift);

    bool ctrlA = e.KeyCode == Keys.A && e.Modifiers == Keys.Control;

    bool editKeys = (
        (e.KeyCode == Keys.Z && e.Modifiers == Keys.Control) ||
        (e.KeyCode == Keys.X && e.Modifiers == Keys.Control) ||
        (e.KeyCode == Keys.C && e.Modifiers == Keys.Control) ||
        (e.KeyCode == Keys.V && e.Modifiers == Keys.Control) ||
        e.KeyCode == Keys.Delete ||
        e.KeyCode == Keys.Back);

    bool navigationKeys = (
        e.KeyCode == Keys.Up ||
        e.KeyCode == Keys.Right ||
        e.KeyCode == Keys.Down ||
        e.KeyCode == Keys.Left ||
        e.KeyCode == Keys.Home ||
        e.KeyCode == Keys.End);

    if (!(numericKeys || editKeys || navigationKeys))
    {
        if (ctrlA)
        // Do select all as OS/Framework
        // does not always seem to implement this.
            SelectAll();
        result = false;
    }
    if (!result) // If not valid key then suppress and handle.
    {
        e.SuppressKeyPress = true;
        e.Handled = true;
        if (ctrlA) { } // Do Nothing!
        else
            OnKeyRejected(new KeyRejectedEventArgs(e.KeyCode));
    }
    else
        base.OnKeyDown(e);
}

CheckPasteValid

When a paste message is received, it's caught in the overridden WndProc, which then calls this method. Based on the result, if necessary, it returns without calling the base's WndProc, therefore cancelling the message. The code for CheckPasteValid is given below. After setting the default values, we attempt to get the text from the clipboard. If there's an error or there's no valid text, then an appropriate reject reason is set and we return. If OK, we then build a string from the current text and the clipboard's text. The final step is to check if the clipboard's text contains any non digit characters and set the required reject reason.

C#
private PasteEventArgs CheckPasteValid()
{
    // Default values.
    PasteRejectReasons rejectReason = PasteRejectReasons.Accepted;
    string originalText = Text;
    string clipboardText = string.Empty;
    string textResult = string.Empty;

    try
    {
        clipboardText = Clipboard.GetText(TextDataFormat.Text);
        if (clipboardText.Length > 0) // Does clipboard contain text?
        {
            // Store text value as it will be post paste assuming it is valid.
            textResult = (
                Text.Remove(SelectionStart, 
                SelectionLength).Insert(SelectionStart, clipboardText));
            foreach (char c in clipboardText) // Check for any non digit characters.
            {
                if (!char.IsDigit(c))
                {
                    rejectReason = PasteRejectReasons.InvalidCharacter;
                    break;
                }
            }
        }
        else
            rejectReason = PasteRejectReasons.NoData;
    }
    catch
    {
        rejectReason = PasteRejectReasons.Unknown;
    }
    return new PasteEventArgs(originalText, clipboardText, textResult, rejectReason);
}

New stuff

Events

  • KeyRejected - Occurs when a KeyDown event is suppressed.
  • PasteRejected - Occurs when a Paste attempt is disallowed.

Properties

  • DefaultText - The string to use when there is no value (cannot be null or empty).

Nested classes

There are two nested event argument classes.

KeyRejectedEventArgs

An instance of this is created every time a key down is suppressed. It has just one property:

  • Key - They rejected key (System.Windows.Forms.Keys).

PasteEventArgs

An instance of this is created every time a Paste message is received. It's used internally, but its primary purpose is as the event args in the PasteRejected event. It has four properties:

  • OriginalText - The text as it was before the paste (or still is, if rejected).
  • ClipboardText - The text that is attempting to paste.
  • TextResult - The text that is or would have been the result of the paste.
  • RejectReason - An enum (PasteRejectReasons) that indicates the reason for rejection if rejected, or PasteRejectReasons.Accepted for internal use if the paste is OK.

History

  • 7 November 2008: Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO Dave Meadowcroft
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThanks, the best solution I ever seen. Pin
Francisco R M27-Oct-20 12:58
Francisco R M27-Oct-20 12:58 
Questionthanks Pin
Member 1145160512-Apr-15 9:20
Member 1145160512-Apr-15 9:20 
GeneralAn alternative method that includes negative and decimal point, with pasting by mouse and keyboard. Pin
AORD15-Nov-13 17:12
AORD15-Nov-13 17:12 
QuestionSimplest method to check if textbox contaions only numbers Pin
Ashish sharma8-Sep-13 6:52
Ashish sharma8-Sep-13 6:52 
AnswerRe: Simplest method to check if textbox contaions only numbers Pin
DaveyM6910-Sep-13 9:52
professionalDaveyM6910-Sep-13 9:52 
QuestionMy vote is +5 Pin
abbaspirmoradi1-Sep-13 20:28
professionalabbaspirmoradi1-Sep-13 20:28 
Suggestiona complete Numerical TextBox for download Pin
Reza_m_n_6531-May-13 10:30
Reza_m_n_6531-May-13 10:30 
GeneralMy vote of 5 Pin
THines013-Dec-11 3:24
THines013-Dec-11 3:24 
NewsAn another silent TextBox to accept number for a range. Pin
Manish K. Agarwal27-Sep-11 1:16
Manish K. Agarwal27-Sep-11 1:16 
GeneralRe: An another silent TextBox to accept number for a range. Pin
DaveyM6928-Sep-11 6:47
professionalDaveyM6928-Sep-11 6:47 
GeneralMy vote of 5 Pin
Sander Rossel4-May-11 10:12
professionalSander Rossel4-May-11 10:12 
Generalhowto add a decimal Pin
Member 197457022-Oct-09 17:04
Member 197457022-Oct-09 17:04 
GeneralRe: howto add a decimal Pin
DaveyM6923-Oct-09 10:45
professionalDaveyM6923-Oct-09 10:45 
QuestionConfused Pin
Xmen Real 2-Apr-09 6:23
professional Xmen Real 2-Apr-09 6:23 
AnswerRe: Confused Pin
DaveyM692-Apr-09 6:29
professionalDaveyM692-Apr-09 6:29 
GeneralRe: Confused Pin
Xmen Real 2-Apr-09 15:43
professional Xmen Real 2-Apr-09 15:43 
Generalvery kool Pin
Donsw7-Feb-09 11:33
Donsw7-Feb-09 11:33 
GeneralRe: very kool Pin
DaveyM698-Feb-09 1:21
professionalDaveyM698-Feb-09 1:21 
GeneralVery simple NumericTextBox for example Pin
-=SerP=-10-Nov-08 20:41
-=SerP=-10-Nov-08 20:41 
GeneralRe: Very simple NumericTextBox for example [modified] Pin
DaveyM6911-Nov-08 1:08
professionalDaveyM6911-Nov-08 1:08 
GeneralRe: Very simple NumericTextBox for example Pin
-Dy7-Jun-09 21:58
-Dy7-Jun-09 21:58 
General[Message Deleted] Pin
Claudio Nicora10-Nov-08 20:40
Claudio Nicora10-Nov-08 20:40 
GeneralRe: Testing all the accepted keys Pin
DaveyM6911-Nov-08 1:38
professionalDaveyM6911-Nov-08 1:38 
GeneralRe: Testing all the accepted keys Pin
Claudio Nicora11-Nov-08 4:45
Claudio Nicora11-Nov-08 4:45 
GeneralRe: Testing all the accepted keys Pin
DaveyM6911-Nov-08 11:45
professionalDaveyM6911-Nov-08 11:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.