Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Numeric TextBox with Automatic Advancing

0.00/5 (No votes)
27 May 2015 1  
This short article presents methods to insure that a TextBox contains only numeric characters and that focus automatically advances to the next input control when the current Textbox is filled.

Table of Contents

Introduction Table of Contents

This article presents methods to

  • Insure that a TextBox contains only decimal digits.
  • Advances the focus to the next input control when the current Textbox is filled.

Background Table of Contents

During a recent project developing a Work Order system for both desktop and mobile use, I needed methods to process TextBox objects in a special way. Certain TextBoxes could only contain decimal digits. Other Textboxes were interrelated.

ZIP Telephone

In the figure to the left, four TextBoxes are located contiguously: ZIP code, telephone area code, telephone prefix, and telephone number. Each TextBox should accept only decimal digits. And, when the proper number of digits is entered, focus should be moved to the next control.

For example, the cursor should be moved to

  • the telephone area code TextBox when the ZIP code TextBox contains five digits.
  • the telephone prefix TextBox when the telephone area code TextBox contains three digits.
  • the telephone number TextBox when the telephone prefix TextBox contains three digits.
  • the next Form control when the telephone number TextBox contains four digits.

Note that advancing from one TextBox to the next is controlled by the MaxLength property of each TextBox.

Implementation Table of Contents

Insuring Decimal Digits Table of Contents

Insuring that only decimal digits are entered into a TextBox is accomplished by handling the TextBox KeyDown event. I named the TextBox KeyDown event handler test_for_decimal_digits and it is attached to each TextBox for which decimal digit testing is desired.

    // ************************************ test_for_decimal_digit

    /// <summary>
    /// 
    /// KeyDown event handler that determines if the character 
    /// corresponding to the key pressed is a Unicode character 
    /// categorized as a control character or categorized as a 
    /// decimal (radix-10) digit (i.e., in the range 0 through 9). 
    /// If the character is not a control character and not a 
    /// decimal digit, it will be silently discarded.
    /// 
    /// This handler will also allow the use of a paste (Ctrl-V) 
    /// operation if the pasted text only contains decimal digits. It 
    /// recognizes input from the numeric keypad.
    /// 
    /// </summary>
    /// <see>
    /// http://www.vcskicks.com/numbers_only_textbox.php
    /// </see>
    /// <revisions>
    /// 20150527  gggustafson  repaired bug that prohibited keypad 
    ///                        digits from being recognized
    /// </revisions>
    void test_for_decimal_digits ( object       sender, 
                                   KeyEventArgs e )
        {
        char    current_key = ( char ) e.KeyCode;
        bool    modifier = e.Control || e.Alt || e.Shift;
        bool    non_numeric = char.IsLetter ( current_key ) ||
                              char.IsSymbol ( current_key ) ||
                              char.IsWhiteSpace ( current_key ) ||
                              char.IsPunctuation ( current_key );
                                    // allow navigation keys
        switch ( e.KeyCode )
            {
            case Keys.Up:
            case Keys.Down:
            case Keys.Left:
            case Keys.Right:
            case Keys.PageUp:
            case Keys.PageDown:
            case Keys.Delete:
                e.SuppressKeyPress = false;
                return;

            default:
                break;
            }
                                    // block non-number characters
        if ( !modifier && non_numeric )
            {
            if ( ( e.KeyCode < Keys.NumPad0 ) || 
                 ( e.KeyCode > Keys.NumPad9 ) )
                {
                e.SuppressKeyPress = true;
                }
            }
                                    // handle pasted text
        if ( e.Control && ( e.KeyCode == Keys.V ) )
            {
                                    // preview pasted data and 
                                    // remove non-digit characters
            string  pasted_text = Clipboard.GetText ( );
            string  stripped_text = String.Empty;

            for ( int i = 0; ( i < pasted_text.Length ); i++ )
                {
                if ( char.IsDigit ( pasted_text [ i ] ) )
                    {
                    stripped_text += pasted_text [ i ];
                    }
                }

            if ( !stripped_text.Equals ( pasted_text ) )
                {
                                        // non-decimal numbers in 
                                        // the pasted text
                e.SuppressKeyPress = true;
                }
            else
                {
                e.SuppressKeyPress = false;
                }
            }
        }

Auto Advancing through Fields Table of Contents

Advancing from one TextBox to the next is accomplished by handling the TextBox TextChanged event. I named the TextBox TextChanged event handler skip_to_next_control and as before it is attached to each TextBox for which automatic skipping out is desired.

    // ************************************** skip_to_next_control

    /// <summary>
    /// 
    /// TextBox TextChanged event handler that requires 
    /// 
    ///     The TextBox MaxLength property be set to the maximum 
    ///     number of characters that will be accepted into the 
    ///     TextBox
    ///     
    ///     The Tab Order be set for the Form, insuring that the 
    ///     next numerically larger TabIndex be set for the next 
    ///     control to gain focus.
    /// 
    /// When the number of characters in the TextBox equals the 
    /// TextBox MaxLength, the cursor will be moved to the next 
    /// control in the Form's TabIndex order.
    /// 
    /// Text appearing in the TextBox is trimmed before length 
    /// testing occurs. If the trimmed string length is not equal 
    /// to the length of the TextBox.Text string, the trimmed 
    /// string will replace the TextBox.Text string.
    /// 
    /// </summary>
    void skip_to_next_control ( object    sender, 
                                EventArgs e )
        {
        TextBox   text_box = ( TextBox ) sender;
        int       length = 0;
        string    original_text = text_box.Text;
        string    trimmed_text = original_text.Trim ( );
                                    // remove leading and trailing 
                                    // whitespace characters from 
                                    // the TextBox text
        if ( original_text.Length != trimmed_text.Length )
            {
            text_box.Text = trimmed_text;
            }
                                    // retrieve length of possibly 
                                    // modified TextBox text
        length = text_box.Text.Length;
                                    // focus cursor on next control
        if ( length == text_box.MaxLength )
            {
                                    // need the parent of the 
                                    // TextBox control because 
                                    // a TextBox is not a 
                                    // container and 
                                    // SelectNextControl only 
                                    // works with containers
            Control parent = text_box.Parent;

            parent.SelectNextControl ( ActiveControl, 
                                       true, 
                                       true, 
                                       true, 
                                       true );
            }
        }

There are some conditions levied against the Form in order to obtain TextBox advancing.

  • The MaxLength of each participating TextBox must be set to the number of characters that, once reached, will cause the focus to be moved to the next control. For example, a ZIP code contains 5 digits, so the MaxLength of the ZIP code TextBox should be set to 5. Likewise, the telephone area code and prefix should have a MaxLength of 3.
  • The TabIndex for contiguous TextBoxes must be monotonically increasing. The Form Tab Order can be set by clicking on View→Tab Order in the Visual Studio Designer menu.

When these conditions are met, automatically advancing from one TextBox to the next can occur.

Attaching Handlers to Multiple Objects Table of Contents

In the Work Order Customer TabPage there are seven TextBoxes to which both event handlers are to be attached. In Visual Studio, it is relatively easy to attach event handlers to multiple objects. In the following figure, the seven TextBoxes are filled with red. I suggest the following procedure when ever it is necessary to attach handlers to more than one TextBoxes:

Attaching Handlers
  1. Make sure that the event handlers you want to attach are in the code behind and that the code behind has compiled without error.
  2. Open the Visual Studio Designer.
  3. Holding down the control key, select all of the TextBoxes to which event handlers will be attached.
  4. At the top of Properties, click Events (the small lightening bolt button). This will open a list of events.
  5. Click on an event name. Move the cursor to the far right of the event row. Left click and a dropdown list of event handlers found in the code behind will appear.
  6. Choose the event handler appropriate to the event.
  7. Repeat these steps for each event handler to be attached.

Downloads Table of Contents

No downloads have been included in this article. The Copy Code link above each source code fragment will copy the code onto the Clipboard.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here