Click here to Skip to main content
15,868,016 members
Articles / Programming Languages / C#

PasswordEye Control

Rate me:
Please Sign up or sign in to vote.
4.90/5 (20 votes)
30 Sep 2013CPOL7 min read 51.1K   3.7K   27   8
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)


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

 
QuestionPasswordEye Control Pin
Mike Bledig27-Sep-22 21:31
Mike Bledig27-Sep-22 21:31 
QuestionPropiedad PasswordChar no se mantiene. Pin
TSS 20206-May-20 23:06
TSS 20206-May-20 23:06 
Questionnaming your downloads Pin
dherrmann7-Oct-13 8:43
dherrmann7-Oct-13 8:43 
AnswerRe: naming your downloads Pin
gggustafson7-Oct-13 9:49
mvagggustafson7-Oct-13 9:49 
GeneralRe: naming your downloads Pin
dherrmann7-Oct-13 10:31
dherrmann7-Oct-13 10:31 
GeneralRe: naming your downloads Pin
gggustafson7-Oct-13 11:21
mvagggustafson7-Oct-13 11:21 
SuggestionRounding Pin
hollysong30-Sep-13 4:13
hollysong30-Sep-13 4:13 
GeneralRe: Rounding Pin
gggustafson30-Sep-13 5:35
mvagggustafson30-Sep-13 5:35 

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.