Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

PasswordEye Control

4.90/5 (20 votes)
30 Sep 2013CPOL7 min read 53K   3.8K  
This article presents a UserControl, named PasswordEye that displays a modern password control.

Introduction [^]

Password Eye

This article presents a UserControl, named PasswordEye, that displays 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 control. When the mouse cursor is placed over the eye and a mouse button pressed, the characters in the TextBox become visible. Upon release of the mouse button, the characters in the TextBox are again hidden by the PasswordChar masking character.

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 [^] returns the reader to the top of the Table of Contents.

Visual Properties [^]

The PasswordEye control has a number of properties that affect the user's visual image. The developer specifies the control's top-left corner by dragging the control from the ToolBox to a position on the form. This position becomes ( 0, 0 ) in the control's graphic environment.

The height and width of the control are specified using the Font and Maximum_Width properties. After some computations, the values of a number of other internal variables are set by the set_control_properties method.

The background color of the control and its components (panel, textbox, and button) is specified by the BackColor property. The background color defaults to Color.White. The foreground color of the control's textbox component is specified by the Forecolor property. The forecolor color defaults to Color.Black.

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

Text displayed in the password TextBox can be retrieved or set by the Text property.

Control Properties [^]

The PasswordEye control has 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.
Font Gets or sets the Font used in the control's TextBox component. The default is the Microsoft Sans Serif font family, regular font style, and font size of 12. Font controls the height of the control.
ForeColor Gets or sets the color of the ForeColor of the control's components. The default value is Color.Black.
Maximum_Width Gets or sets the maximum width, in characters, of the control's TextBox. Maximum_Width only affects the width of the control. The default value is 20.
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.
PasswordChar   Gets or sets the character used to mask input into the control's Textbox. The default is the asterisk (*).
Text Gets or sets the text that appears in the control's TextBox.

When certain properties are changed, other internal values for the control are recalculated by the set_control_properties method.

Implementation [^]

PasswordEye Components

The PasswordEye control is a UserControl composed of a Panel, a TextBox, and a Button. Each component has a one pixel buffer around it.

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 value of any property changes

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

void set_control_properties ( )
    {
    int button_location_y = 0;
                                // remove all components from
                                // the control
    this.Controls.Clear ( );
                                // remove all components from
                                // the panel
    panel.Controls.Clear ( );
                                // process textbox first; the
                                // textbox width is dependent
                                // on the Font and the
                                // Max_Display properties; in
                                // turn the textbox properties
                                // drive most of the control's
                                // other properties
    textbox.BackColor = backcolor;
    textbox.BorderStyle = BorderStyle.None;
    textbox.ForeColor = forecolor;
                                // textbox location within
                                // panel is fixed
    textbox.Location = new Point ( TEXTBOX_LOCATION_X,
                                   TEXTBOX_LOCATION_Y );
    textbox.Size = new Size ( textbox_text_width ( ),
                              textbox.Height );
                                // process button next; the
                                // panel width depends upon
                                // both the textbox and button
                                // properties
    button.BackColor = backcolor;
    button.BackgroundImage = Properties.
                             Resources.
                             PasswordEyeImage;
    button.BackgroundImageLayout = ImageLayout.Zoom;
    button.FlatStyle = FlatStyle.Flat;
                                // when the textbox.Height is
                                // greater than TEXTBOX_HEIGHT
                                // the button.Size takes on
                                // the value
                                //      ( BUTTON_HEIGHT,
                                //        BUTTON_WIDTH )
                                // and the button is centered
                                // vertically with respect to
                                // the textbox
    if ( textbox.Height > TEXTBOX_HEIGHT )
        {
        button.Size = new Size ( BUTTON_HEIGHT,
                                 BUTTON_WIDTH );
        button_location_y =
            round ( ( double ) ( textbox.Height -
                                 button.Height ) / 2.0 );
        }
    else
        {
        button.Size = new Size ( textbox.Height,
                                 textbox.Height );
        button_location_y = textbox.Location.Y;
        }
    button.Location = new Point ( textbox.Location.X +
                                      textbox.Width + 1,
                                  button_location_y );
                                // process panel
    panel.BackColor = backcolor;
                                // panel location within
                                // control is fixed
    panel.Location = new Point ( PANEL_LOCATION_X,
                                 PANEL_LOCATION_Y );
    panel.Size = new Size (
                                // space preceeds textbox
                            ( textbox.Location.X + 1 ) +
                                // space follows textbox
                                ( textbox.Width + 1 ) +
                                // space follows button
                                ( button.Width + 1 ),
                                // space at top and bottom
                            ( textbox.Height + 2 ) );
                                // add back the TextBox and
                                // the Button to the Panel's
                                // control collection
    panel.Controls.Add ( textbox );
    panel.Controls.Add ( button );
                                // add back the Panel to the
                                // control's control
                                // collection
    this.Controls.Add ( panel );
                                // adjust the width and height
                                // of the control by adding a
                                // pixel at the right, left,
                                // top, and bottom
    this.Width = panel.Width + 2;
    this.Height = panel.Height + 2;
                                // advise any subscriber that
                                // the control properties have
                                // changed
    trigger_passwordeye_properties_changed_event ( );
    }

set_control_properties performs the following actions, in order:

  • Clears the control's ControlCollection thus removing existing textbox, button, or panel components from the control.
  • Clears the panel's ControlCollection thus removing existing textbox and button components from the panel.
  • Revises the properties of the control's TextBox.
  • Revises the properties of the control's Button.
  • Revises the properties of the control's Panel.
  • Adds the revised TextBox and Button back into the Panel's ControlCollection.
  • Adds the revised Panel back into the control's ControlCollection.
  • Adjusts the size of the control.
  • Invokes trigger_passwordeye_properties_changed_event to notify any subscriber of changes to the control's and control components' properties.

The helper function round is:

C#
// ***************************************************** round

// http://en.wikipedia.org/wiki/Rounding#Round_half_up


int round ( double control_value )
    {

    return ( ( int ) ( control_value + 0.5 ) );
    }

Handling Events [^]

Many programming languages have a mechanism whereby events of interest can be signaled to interested parties. C# has such a mechanism and, because PasswordEye is implemented in C#, this discussion will be limited to that language.

PasswordEyePropertiesChanged [^]

PasswordEye usefulness is increased if it could tell (signal) its parent that the user made a change to PasswordEye properties. To signal these events, PasswordEye contains the declaration of the PasswordEyePropertiesChanged event.

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

public delegate void PasswordEyePropertiesChangedHandler (
                Object                                sender,
                PasswordEyePropertiesChangedEventArgs e );

public event PasswordEyePropertiesChangedHandler
                    PasswordEyePropertiesChanged;

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

C#
// ******************* class PasswordEyePropertiesChangedEventArgs

public class PasswordEyePropertiesChangedEventArgs
    {
    public Color   backcolor;
    public Button  button;
    public Control control;
    public Color   forecolor;
    public int     maximum_width;
    public Panel   panel;
    public TextBox textbox;

    // ********************* PasswordEyePropertiesChangedEventArgs

    public PasswordEyePropertiesChangedEventArgs (
                                            Color   backcolor,
                                            Button  button,
                                            Control control,
                                            Color   forecolor,
                                            int     maximum_width,
                                            Panel   panel,
                                            TextBox textbox )
        {

        this.backcolor = backcolor;
        this.button = button;
        this.control = control;
        this.forecolor = forecolor;
        this.maximum_width = maximum_width;
        this.panel = panel;
        this.textbox = textbox;
        }

    } // class PasswordEyePropertiesChangedEventArgs

PasswordEyePropertiesChangedEventArgs returns the current background and foreground colors, button, panel, and textbox components, the current maximum_width, and the control, itself. Whenever PasswordEye detects a change in the value of any control component properties, it invokes the trigger_passwordeye_properties_changed_event method.

C#
// ************** trigger_passwordeye_properties_changed_event

void trigger_passwordeye_properties_changed_event ( )
    {

    if ( PasswordEyePropertiesChanged != null )
        {
        PasswordEyePropertiesChanged (
            this,
            new PasswordEyePropertiesChangedEventArgs (
                                        backcolor,
                                        button,
                                        this,
                                        forecolor,
                                        textbox_maximum_width,
                                        panel,
                                        textbox ) );
        }
    }

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

C#
if ( PasswordEyePropertiesChanged != null )

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

If a class wishes to be notified of a change in the value of the PasswordEye properties, it must register an event handler. In the Demonstration program there is a single PasswordEye instance. The Demonstration program subscribes to the event handler of this instance. This is accomplished by first declaring that the method password_PE_PasswordEyePropertiesChanged is to be used to capture the event:

C#
password_PE.PasswordEyePropertiesChanged +=
    new PasswordEye.
        PasswordEye.
        PasswordEyePropertiesChangedHandler (
            password_PE_PasswordEyePropertiesChanged );

The PasswordEyePropertiesChanged method is declared as:

C#
// ****************************** PasswordEyePropertiesChanged

void password_PE_PasswordEyePropertiesChanged (
    object                                            sender,
    PasswordEye.PasswordEyePropertiesChangedEventArgs e )
    {

    control_status =
        String.Format (
            "      Textbox: Location {3:D3}, {4:D3}" +
            Environment.NewLine +
            "               Size {5:D3}, {6:D3}" +
            Environment.NewLine +
            "               Text: {18}" +
            Environment.NewLine +
            "               Font:" +
            Environment.NewLine +
            "                   Size {0}" +
            Environment.NewLine +
            "                   Name {1}" +
            Environment.NewLine +
            "                   Style {2}" +
            Environment.NewLine +
            "               MaxLength: {17}" +
            Environment.NewLine +
            "               Password Char: {19}" +
            Environment.NewLine +
            "               Max_Width: {24}" +
            Environment.NewLine +
            "       Button: Location {7:D3}, {8:D3}" +
            Environment.NewLine +
            "               Size {9:D3}, {10:D3}" +
            Environment.NewLine +
            "        Panel: Location {11:D3}, {12:D3}" +
            Environment.NewLine +
            "               Size {13:D3}, {14:D3}" +
            Environment.NewLine +
            "       Colors: Back {15}" +
            Environment.NewLine +
            "               Fore {16}" +
            Environment.NewLine +
            "      Control: Location {20:D3}, {21:D3}" +
            Environment.NewLine +
            "               Size {22:D3}, {23:D3}",
            e.textbox.Font.Size,
            e.textbox.Font.FontFamily.ToString ( ),
            e.textbox.Font.Style.ToString ( ),
            e.textbox.Location.X,
            e.textbox.Location.Y,
            e.textbox.Size.Width,
            e.textbox.Size.Height,
            e.button.Location.X,
            e.button.Location.Y,
            e.button.Size.Width,
            e.button.Size.Height,
            e.panel.Location.X,
            e.panel.Location.Y,
            e.panel.Size.Width,
            e.panel.Size.Height,
            e.backcolor.ToString ( ),
            e.forecolor.ToString ( ),
            e.textbox.MaxLength,
            e.textbox.Text,
            e.textbox.PasswordChar,
            e.control.Location.X,
            e.control.Location.Y,
            e.control.Size.Width,
            e.control.Size.Height,
            e.maximum_width );

    display_information ( );
    }

The Eye [^]

The user interacts with the PasswordEye 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 for the OnMouseDown and OnMouseUp events.

button_MouseDown Event Handler [^]

button_MouseDown is the handler for the OnMouseDown event.

C#
// ****************************************** button_MouseDown

void button_MouseDown ( object         sender,
                        MouseEventArgs e )
    {

    base.OnMouseDown ( e );

    textbox.PasswordChar = PASSWORD_VISIBLE;
    }

The button_MouseDown event handler is classic.

  1. Call the base class's OnMouseDown method so that all registered delegates receive the event.
  2. Set the textbox PasswordChar to PASSWORD_VISIBLE ('\0'). This has the effect of showing the current contents of the textbox.
button_MouseUp Event Handler [^]

button_MouseUp handles the OnMouseUp event.

C#
// ******************************************** button_MouseUp

void button_MouseUp ( object         sender,
                      MouseEventArgs e )
    {

    base.OnMouseUp ( e );

    textbox.PasswordChar = PASSWORD_HIDDEN;
    }

When the user releases the mouse button, the button_OnMouseUp event handler is invoked. This handler simply sets the textbox PasswordChar to PASSWORD_HIDDEN ('*'), effectively hiding what has been typed into the textbox.

TextBox Events [^]

textbox_TextChanged Event Handler [^]

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

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

void textbox_TextChanged ( object    sender,
                           EventArgs e )
    {

    base.OnTextChanged ( e );

    trigger_passwordeye_properties_changed_event ( );
    }

All that textbox_TextChanged does is to trigger the PasswordEyePropertiesChangedEvent event. Any subscriber to that event will obtain the current properties of the PasswordEye control, including the characters typed into the password textbox.

textbox_FontChanged Event Handler [^]

There are two properties that define the size of the PasswordEye control: Font and Maximum_Width. Both are provided for the developer. In the Demonstration program both values may be changed dynamically. Changes in either of the properties' values will cause an invocation of set_control_properties. In addition, any dynamic change to Font will trigger the textbox_FontChanged event handler.

C#
// *************************************** textbox_FontChanged

void textbox_FontChanged ( object    sender,
                           EventArgs e )
    {

    base.OnFontChanged ( e );

    set_control_properties ( );
    }

Demonstration [^]

Demonstration

The demonstration program shows how the PasswordEye control works. It allows its user to play around with the control's properties. As property values change, their values are displayed in the RichTextBox.

Conclusion [^]

This article has presented a UserControl that displays a modern password control.

References [^]

Development Environment [^]

The PasswordEye control was 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 [^]

09/29/2013   Original Article.
09/30/2013   Made typographic corrections.

License

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