Click here to Skip to main content
15,885,216 members
Articles / Programming Languages / C#

PasswordXEye and TextBoxX Controls

Rate me:
Please Sign up or sign in to vote.
4.64/5 (16 votes)
19 Sep 2014CPOL12 min read 28.3K   1.2K   25   12
This article presents two UserControls, PasswordXEye and TextBoxX, that extend the functionality of the underlying PasswordEye and TextBox controls.

Warning

Some readers, who have downloaded this software onto machines with operating systems other than Windows 7, have reported difficulties with the PasswordXEye control. See Comments and Discussions, below.

Please be forewarned.

Introduction [toc]

PasswordXEye TextBoxX
PasswordX Eye TextBoxX

There has been a recent trend to add "delete text" functionality to the TextBox Class [^] by adding a small "X" to the right of the TextBox. When clicked, the content of the TextBox is cleared.

This article presents two UserControl [^]s:

  1. PasswordXEye, that extends the functionality of the PasswordEye Control [^].
  2. TextBoxX, that extends the functionality of the TextBox Class

Recall that the PasswordEye Control displayed characters in a TextBox masked by a PasswordChar [^] masking character. There is a small Button [^] with a BackgroundImage [^] of an eye on the right side of the PasswordEye control. When the mouse cursor is placed over the eye and a mouse button pressed, the characters in the PasswordEye TextBox become visible. Upon release of the mouse button, the characters in the PasswordEye TextBox are again hidden by the PasswordChar masking character.

The PasswordXEye control adds an additional Button with a BackgroundImage of the letter "X" to the right side of the control, just to the left of the eye. Likewise, the TextBoxX control adds a Button with a BackgroundImage of the letter "X" to the right side of the control. In both controls, when the cursor is placed over the "X" and a mouse button is clicked, the characters in the control's TextBox are cleared and the cursor is positioned to the far left of the control.

In the following discussions, properties that are specified by the developer are displayed in BoldMixedCase text. Variables, used internally by the software, are displayed in italicized_lowercase text.

Table of Contents

The symbol [toc] returns the reader to the top of the Table of Contents.

Visual Properties [toc]

Both the PasswordXEye and the TextBoxX controls have properties that affect the user's visual image. The developer specifies the controls' top-left corner by dragging the control from the ToolBox to a position on the form. This position becomes ( 0, 0 ) in the controls' graphic environment.

Note

The process used to set the height and width of the PasswordXEye components (textbox and eye_button) differs from that used in the earlier PasswordEye control.

The height and width of both the PasswordXEye and the TextBoxX controls are specified using the resizing handles of the Visual Studio Designer [^] or by modifying the the height and the width of the control by setting a new value for the control's Size [^] property. The control's width sets the horizontal position of the control components (textbox, x_button, and, in the case of the PasswordXEye control, the eye_button). The control's height sets the heights of the individual control components. If the control is resized, the values of the width and height of these components are set by the set_control_properties method.

The background color of both controls and their components is specified by the BackColor property. The background color defaults to Color.White. The foreground color of both controls and their components is specified by the Forecolor property. The forecolor color defaults to SystemColors.ControlText.

The character used in the PasswordXEye control for masking the password is specified using the PasswordChar property. The password masking character defaults to the asterisk (*).

Text displayed in both the PasswordXEye and TextBoxX controls can be retrieved or set by the Text property.

Control Properties [toc]

Shared Control Properties [toc]

The PasswordXEye and TextBoxX controls share the following properties available to the developer:

Name Description
BackColor Gets or sets the color of the BackColor of the control's components. The default value is Color.White.
ForeColor Gets or sets the color of the ForeColor of the control's components. The default value is SystemColors.Black.
Text Gets or sets the text that appears in the control's TextBox.

PasswordXEye Control Properties [toc]

The PasswordXEye control has the following additional property available to the developer:

Name Description
PasswordChar Gets or sets the character used to mask input into the control's Textbox. The default is the asterisk (*).

TextBoxX Control Properties [toc]

The TextBoxX control has the following additional property available to the developer:

Name Description
MaxLength Gets or sets the maximum number of characters allowed to be entered into the control's TextBox. MaxLength only affects the number of characters that may be entered into the control's textbox. The default value is 20.

Resizing a Control [toc]

When either control is resized, other values for the control are recalculated by the set_control_properties method.

Implementation [toc]

Because the PasswordXEye control is more complex than the TextBoxX control, the implementation of the PasswordXEye control will be described.

PasswordXEye Implementation [toc]

PasswordXEye Components

The PasswordXEye control is a UserControl composed of a Panel (panel), a TextBox (textbox), and two Buttons (x_button and eye_button).

PasswordXEye Components Offsets

The textbox component has a one pixel offset separating it from the panel and the x-button. Each of the two Buttons also has a one pixel offset separating it from the other and from the bottom of the panel. Because of Button geometry, each Button has a two pixel offset between its top and the panel.

Note

The control uses Windows coordinates with the x-axis values increasing to the right and the y-axis values increasing downward.

set_control_properties is invoked when the control is resized.

C#
// ************************************ set_control_properties

// user has set the desired size of the control from the
// designer either by dragging the resize handles or by
// supplying values in the Size property

void set_control_properties ( )
    {
    Size  button_size;
                                // remove panel components
    if ( panel.Controls.Count > 0 )
        {
        panel.Controls.Clear ( );
        }
                                // remove control components
    if ( this.Controls.Count > 0 )
        {
        this.Controls.Clear ( );
        }
                                // on all sides, panel has a 1
                                // pixel offset from control
    panel.Size = new Size ( this.Size.Width - 2 * OFFSET,
                            this.Size.Height - 2 * OFFSET );
    panel.Location = new Point ( OFFSET, OFFSET );
    panel.BackColor = this.BackColor;
    panel.ForeColor = this.ForeColor;
                                // both buttons are square and
                                // have a 2 pixel offset from
                                // the top of the panel and a
                                // 1 pixel offset from the
                                // bottom of the panel
    button_size = new Size ( panel.Size.Height - 3 * OFFSET,
                             panel.Size.Height - 3 * OFFSET );
                                // process eye button first
    eye_button.Size = button_size;
                                // both buttons have a 2 pixel
                                // offset from the top of the
                                // panel
    eye_button.Location = new Point (
        panel.Size.Width - OFFSET - eye_button.Size.Width,
        2 * OFFSET );
    eye_button.BackColor = this.BackColor;
    eye_button.BackgroundImage =
        Properties.Resources.EyeImage;
    eye_button.BackgroundImageLayout = ImageLayout.Zoom;
    eye_button.FlatAppearance.BorderColor = Color.White;
    eye_button.FlatAppearance.BorderSize = 0;
    eye_button.FlatAppearance.MouseDownBackColor =
        Color.White;
    eye_button.FlatAppearance.MouseOverBackColor =
        Color.White;
    eye_button.FlatStyle = FlatStyle.Flat;
                                // process x_button
    x_button.Size = button_size;
    x_button.Location = new Point (
        eye_button.Location.X - OFFSET - x_button.Size.Width,
        2 * OFFSET );
    x_button.BackColor = this.BackColor;
    x_button.BackgroundImage = Properties.Resources.XImage;
    x_button.BackgroundImageLayout = ImageLayout.Zoom;
    x_button.FlatAppearance.BorderColor = Color.White;
    x_button.FlatAppearance.BorderSize = 0;
    x_button.FlatAppearance.MouseDownBackColor = Color.White;
    x_button.FlatAppearance.MouseOverBackColor = Color.White;
    x_button.FlatStyle = FlatStyle.Flat;
                                // textbox fills panel to the
                                // left and has a 1 pixel
                                // offset from panel and from
                                // x_button
    textbox.Size = new Size (
        x_button.Location.X - 2 * OFFSET,
        panel.Size.Height - 2 * OFFSET );
                                // textbox location is fixed
                                // within panel
    textbox.Location = new Point ( OFFSET, OFFSET );
    textbox.BackColor = this.BackColor;
    textbox.BorderStyle = BorderStyle.None;
    textbox.Font = this.Font;
    textbox.ForeColor = this.ForeColor;
                                // place textbox and buttons
                                // into the panel control
                                // collection
    panel.Controls.Add ( textbox );
    panel.Controls.Add ( x_button );
    panel.Controls.Add ( eye_button );
                                // place panel into the
                                // control's control
                                // collection
    this.Controls.Add ( panel );
    }

set_control_properties performs the following actions, in order:

  • Clears the panel's ControlCollection [^], thus removing any existing TextBox and Button components from the Panel.
  • Clears the control's ControlCollection, thus removing any existing panel component from the control.
  • Revises the properties of the panel. Note here that the panel Size is computed from the PasswordXEye control's Size.
  • Determines the Size of both Buttons from the panel Size.
  • Revises the properties of the eye_button component from the panel Size and the eye_button Size.
  • Revises the properties of the x_button component from the eye_button Location and the x_button Size.
  • Revises the properties of the textbox component from the x_button Location and the panel Size.
  • Places the textbox, x_button, and eye_button components into the panel control collection.
  • Places the panel component into the control's control collection.

TextBoxX Implementation [toc]

The TextBoxX control is a UserControl composed of a Panel (panel), a TextBox (textbox), and one Button (x_button). The TextBoxX control is less complex than the PasswordXEye control by not containing an eye_button.

TextBoxX Components

Because the TextBoxX control is less complex than the PasswordXEye control, the implementation of the set_control_properties for the TextBoxX control is also less complex.

TextBoxX Components Offsets

The textbox component has a one pixel offset separating it from the panel and the x_button. The x_button also has a one pixel offset separating it from bottom and right side of the panel. Because of Button geometry, the x_button has a two pixel offset between its top and the panel.

The set_control_properties for the TextBoxX control is almost the same as that for the PasswordXEye control except that the code that sets the properties for the eye_button has been removed.

Handling Events [toc]

This section describes the events defined by the PasswordXEye and TextBoxX controls and the event handlers in the applications that incorporate the controls.

PasswordXEye Event Handling [toc]

This section details how PasswordXEye handles events. To readers familiar with the PasswordEye (note missing "X"), PasswordXEye has a much simplified PasswordXEyeTextChangedEventArgs.

PasswordXEyeTextChanged [toc]

PasswordXEye usefulness is increased by signaling its parent that the user made a change to the PasswordXEye text. To signal this event, PasswordXEye contains the declaration of the PasswordXEyeTextChanged event.

C#
// ******************************** control delegate and event

public delegate void PasswordXEyeTextChangedHandler (
                    Object                           sender,
                    PasswordXEyeTextChangedEventArgs e );

public event PasswordXEyeTextChangedHandler
                    PasswordXEyeTextChanged;

The delegate [^] PasswordXEyeTextChangedHandler defines the signature of a method that will be invoked by the PasswordXEyeTextChanged event. The event handler is expected to have two arguments: sender and a custom EventArgs, PasswordXEyeTextChangedEventArgs. The latter argument is defined in the following class.

C#
// ************************ class PasswordXEyeTextChangedEventArgs

public class PasswordXEyeTextChangedEventArgs
    {
    public string  Text;

    // ************************** PasswordXEyeTextChangedEventArgs

    public PasswordXEyeTextChangedEventArgs ( string  text )
        {

        Text = text;
        }

    } // class PasswordXEyeTextChangedEventArgs

PasswordXEyeTextChangedEventArgs returns the current text in the Text component. Whenever PasswordXEye detects a change in the value of the text, it invokes the trigger_passwordxeye_text_changed_event method.

C#
// ******************* trigger_passwordxeye_text_changed_event

void trigger_passwordxeye_text_changed_event ( )
    {

    if ( PasswordXEyeTextChanged != null )
        {
        PasswordXEyeTextChanged (
            this,
            new PasswordXEyeTextChangedEventArgs (
                                        textbox.Text ) );
        }
    }

The PasswordXEyeTextChanged event may have zero or more subscribers. The test

C#
if ( PasswordXEyeTextChanged != null )

is made to insure that there is at least one subscriber to the PasswordXEyeTextChanged event. Failure to make this test could cause an exception, something to be avoided in a user control.

If an application wishes to be notified of a change in the value of the PasswordXEye text, it must register [^] an event handler. In the Demonstration program there is a single PasswordXEye instance (PasswordXEye_PXE). The Demonstration program subscribes to the event handler of this instance. This is accomplished by first declaring that the method PasswordXEyeTextChanged is to be used to capture the event:

C#
PasswordXEye_PXE.PasswordXEyeTextChanged +=
    new PasswordXEye.PasswordXEye.
        PasswordXEyeTextChangedHandler (
            PasswordXEyeTextChanged );

The PasswordXEyeTextChanged method is declared as:

C#
// *********************************** PasswordXEyeTextChanged

void PasswordXEyeTextChanged (
            object sender,
            PasswordXEye.PasswordXEyeTextChangedEventArgs e )
    {

    captured_passwordxeye_text_TB.Text = e.Text;
    }

All that this event handler does is to transfer the Text in the PasswordXEyeTextChangedEventArgs to the Text of a local TextBox.

The Eye [toc]

The user interacts with the PasswordXEye control by typing a password into the control. If the user wants to see what has already been entered, the user clicks on the image of an eye on the right side of the control. The user's interactions are detected by the event handlers eye_button_MouseDown and eye_button_MouseUp.

C#
// ************************************** eye_button_MouseDown

void eye_button_MouseDown ( object         sender,
                            MouseEventArgs e )
    {

    textbox.PasswordChar = PASSWORD_VISIBLE;
    }

// **************************************** eye_button_MouseUp

void eye_button_MouseUp ( object         sender,
                          MouseEventArgs e )
    {

    textbox.PasswordChar = PASSWORD_HIDDEN;
    }

The eye_button_MouseDown event handler is triggered by the Control.MouseDown Event [^] and sets the textbox PasswordChar to PASSWORD_VISIBLE ('\0'). This has the effect of showing the current textbox contents.

The eye_button_MouseUp event handler is triggered by the Control.MouseUp Event [^] and sets the textbox PasswordChar to PASSWORD_HIDDEN ('*'), effectively hiding what has been typed into the textbox.

TextBox Events [toc]

PasswordXEye also has two event handlers that process events triggered by the x_button and changes to the contents of the textbox.

C#
// ****************************************** x_button_MouseUp

void x_button_MouseUp ( object         sender,
                        MouseEventArgs e )
    {

    textbox.Text = String.Empty;
    textbox.Focus ( );
    textbox.Select ( 0, 0 );

    trigger_passwordxeye_text_changed_event ( );
    }

The x_button_MouseUp event handler is triggered when the user releases a mouse button over x_button (triggered by the Control.MouseUp Event). When this event handler is triggered, it clears the current contents of the textbox, sets focus to the textbox, and places the insertion caret to the beginning of the textbox. Because the Text in the textbox has changed, the event handler invokes trigger_passwordxeye_text_changed_event.

C#
// *************************************** textbox_TextChanged

void textbox_TextChanged ( object    sender,
                           EventArgs e )
    {

    trigger_passwordxeye_text_changed_event ( );
    }

The textbox_TextChanged event handler is triggered by the Control.TextChanged Event [^] and invokes trigger_passwordxeye_text_changed_event.

TextBoxX Event Handling [toc]

The preceding discussion of the PasswordXEye control is really all that is needed to understand the workings of the TextBoxX control. The two controls operate almost exactly the same except that TextBoxX does not have an eye_button. This section is really only provided for completeness.

TextBoxXTextChanged [toc]

Like PasswordXEye, TextBoxX signals its parent that the user made a change to the TextBoxX text. TextBoxX contains the declaration of the TextBoxXTextChanged event.

C#
// ******************************** control delegate and event

public delegate void TextBoxXTextChangedHandler (
                    Object                           sender,
                    TextBoxXTextChangedEventArgs e );

public event TextBoxXTextChangedHandler TextBoxXTextChanged;

The delegate TextBoxXTextChangedHandler defines the signature of a method that will be invoked by the TextBoxXTextChanged event. The event handler is expected to have two arguments: sender and a custom EventArgs, TextBoxXTextChangedEventArgs. The latter argument is defined in the following class.

C#
// ************************ class TextBoxXTextChangedEventArgs

public class TextBoxXTextChangedEventArgs
    {
    public string  Text;

    // ************************** TextBoxXTextChangedEventArgs

    public TextBoxXTextChangedEventArgs ( string  text )
        {

        Text = text;
        }

    } // class TextBoxXTextChangedEventArgs

TextBoxXTextChangedEventArgs returns the current text in the textbox component. Whenever TextBoxX detects a change in the value of the text, it invokes the trigger_textboxx_text_changed_event method.

C#
// ******************* trigger_textboxx_text_changed_event

void trigger_textboxx_text_changed_event ( )
    {

    if ( TextBoxXTextChanged != null )
        {
        TextBoxXTextChanged (
            this,
            new TextBoxXTextChangedEventArgs (
                                        textbox.Text ) );
        }
    }

The TextBoxXTextChanged event may have zero or more subscribers. The test

C#
if ( TextBoxXTextChanged != null )

is made to insure that there is at least one subscriber to the TextBoxXTextChanged event. Failure to make this test could cause an exception, something to be avoided in a user control.

If an application wishes to be notified of a change in the value of the TextBoxX text, it must register an event handler. In the Demonstration program there is a single TextBoxX instance (textboxx_TBX). The Demonstration program subscribes to the event handler of this instance. This is accomplished by first declaring that the method TextBoxXTextChanged is to be used to capture the event:

C#
textboxx_TBX.TextBoxXTextChanged +=
    new TextBoxX.TextBoxX.
        TextBoxXTextChangedHandler (
            textboxx_TBX_TextBoxXTextChanged );

The TextBoxXTextChanged method is declared as:

C#
// *************************************** TextBoxXTextChanged

void TextBoxXTextChanged (
                    object sender,
                    TextBoxX.TextBoxXTextChangedEventArgs e )
    {

    captured_textboxx_text_TB.Text = e.Text;
    }

All that this event handler does is to transfer the Text in the TextBoxXTextChangedEventArgs to the Text of a local TextBox.

textbox_TextChanged and x_button_Click Event Handlers [toc]

TextBoxX has two event handlers that process events triggered by the x_button and changes to the contents of the textbox.

C#
// ******************************************** x_button_Click

void x_button_Click ( object sender, EventArgs e )
    {

    textbox.Text = String.Empty;
    textbox.Focus ( );
    textbox.Select ( 0, 0 );

    trigger_textboxx_text_changed_event ( );
    }

The x_button_Click event handler is triggered when the user clicks on the over x_button (triggered by the Control.Click Event [^]). When this event handler is triggered, it clears the current contents of the textbox, sets focus to the textbox, and places the insertion caret to the beginning of the textbox. Because the Text in the textbox has changed, the event handler invokes trigger_passwordxeye_text_changed_event.

Each character typed into the TextBoxX textbox triggers the textbox_TextChanged event.

C#
// *************************************** textbox_TextChanged

void textbox_TextChanged ( object    sender,
                           EventArgs e )
    {

    trigger_textboxx_text_changed_event ( );
    }

The textbox_TextChanged event handler is triggered by the Control.TextChanged Event and invokes trigger_textboxx_text_changed_event.

If the user clicks the x_button the x_button_Click event handler is triggered.

C#
// ******************************************** x_button_Click

void x_button_Click ( object sender, EventArgs e )
    {

    textbox.Text = String.Empty;
    textbox.Focus ( );
    textbox.Select ( 0, 0 );

    trigger_textboxx_text_changed_event ( );
    }

When this event handler is triggered, it clears the current contents of the textbox, sets focus to the textbox, and places the insertion caret to the beginning of the textbox. Because the Text in the textbox has changed, the event handler invokes trigger_textboxx_text_changed_event.

Caution [toc]

I recommend that resizing the control be performed in the Visual Studio Designer and not programmatically. Because the control modifies the size of its components, thereby triggering an invocation of either trigger_passwordxeye_text_changed_event or trigger_textboxx_text_changed_event, the text in the textbox component at the time of resizing may be lost.

I have been informed by readers that the PasswordXEye control is misbehaving in Windows XP and Windows 8. Because I do not have access to those operating systems, I request that anyone having fixed the problem please advise me.

Demonstration [toc]

Demonstration

The demonstration program shows how the PasswordXEye and TextBoxX controls work.

Conclusion [toc]

This article has presented two UserControls, PasswordXEye and TextBoxX, that extend the functionality of the underlying PasswordEye and TextBox controls by incorporating a trend in control implementations.

References [toc]

Development Environment [toc]

The PasswordXEye and TextBoxX controls were developed in the following environment:

Microsoft Windows 7 Professional Service Pack 1
Microsoft Visual Studio 2008 Professional
Microsoft .Net Framework Version 3.5 SP1
Microsoft Visual C# 2008

History [toc]

09/16/2014 Original Article.

License

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


Written By
Software Developer (Senior)
United States United States
In 1964, I was in the US Coast Guard when I wrote my first program. It was written in RPG (note no suffixing numbers). Programs and data were entered using punched cards. Turnaround was about 3 hours. So much for the "good old days!"

In 1970, when assigned to Washington DC, I started my MS in Mechanical Engineering. I specialized in Transportation. Untold hours in statistical theory and practice were required, forcing me to use the university computer and learn the FORTRAN language, still using punched cards!

In 1973, I was employed by the Norfolk VA Police Department as a crime analyst for the High Intensity Target program. There, I was still using punched cards!

In 1973, I joined Computer Sciences Corporation (CSC). There, for the first time, I was introduced to a terminal with the ability to edit, compile, link, and test my programs on-line. CSC also gave me the opportunity to discuss technical issues with some of the brightest minds I've encountered during my career.

In 1975, I moved to San Diego to head up an IR&D project, BIODAB. I returned to school (UCSD) and took up Software Engineering at the graduate level. After BIODAB, I headed up a team that fixed a stalled project. I then headed up one of the two most satisfying projects of my career, the Automated Flight Operations Center at Ft. Irwin, CA.

I left Anteon Corporation (the successor to CSC on a major contract) and moved to Pensacola, FL. For a small company I built their firewall, given free to the company's customers. An opportunity to build an air traffic controller trainer arose. This was the other most satisfying project of my career.

Today, I consider myself capable.

Comments and Discussions

 
QuestionWin 8.1 problem Pin
Brian Stevens20-Sep-14 15:42
Brian Stevens20-Sep-14 15:42 
AnswerRe: Win 8.1 problem Pin
Brian Stevens20-Sep-14 15:46
Brian Stevens20-Sep-14 15:46 
GeneralRe: Win 8.1 problem Pin
gggustafson20-Sep-14 16:00
mvagggustafson20-Sep-14 16:00 
AnswerRe: Win 8.1 problem Pin
gggustafson20-Sep-14 15:58
mvagggustafson20-Sep-14 15:58 
QuestionControl missing Pin
Member 420890619-Sep-14 9:58
Member 420890619-Sep-14 9:58 
AnswerRe: Control missing Pin
gggustafson19-Sep-14 10:13
mvagggustafson19-Sep-14 10:13 
BugSame problem, not working on Win 8.1 Pin
Brian Stevens18-Sep-14 13:31
Brian Stevens18-Sep-14 13:31 
GeneralRe: Same problem, not working on Win 8.1 Pin
gggustafson19-Sep-14 5:29
mvagggustafson19-Sep-14 5:29 
BugNot working on Windows XP Pin
MrFloydARG17-Sep-14 6:56
professionalMrFloydARG17-Sep-14 6:56 
GeneralRe: Not working on Windows XP Pin
gggustafson17-Sep-14 7:24
mvagggustafson17-Sep-14 7:24 
BugNot working in Win 8.1 Pin
Jackson Savitraz16-Sep-14 18:08
professionalJackson Savitraz16-Sep-14 18:08 
AnswerRe: Not working in Win 8.1 Pin
gggustafson17-Sep-14 2:26
mvagggustafson17-Sep-14 2:26 

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.