Microsoft Most Valuable Professional

Chris Pietschmann

An MVP From Wisconsin



PasswordTextBox for Silverlight 2 Beta 2

The standard TextBox control that is built into Silverlight 2 Beta 2 is a bit lacking and is missing alot of features that we have become accustomed to in a TextBox. One of those features is being able to mask the characters being displayed when its used to accept passwords. Here's a small PasswordTextBox control I built that does just that; it masks the characters from being displayed so you can accept passwords like you're used to.

Update 6/7/2008 - I just tested this with Silverlight 2 Beta 2 and it works just the same as it does with Beta 1. 

Updated 3/17/2008 - I updated this code to support the Delete and Backspace keys, and to maintain caret/cursor position within the box. I also added the PasswordChar property that defines what the masking character is used to hide the password entered.

/// Copyright 2008 Chris Pietschmann (http://pietschsoft.com)
/// This work is licensed under a Creative Commons Attribution 3.0 United States License
/// http://creativecommons.org/licenses/by/3.0/us/
///
/// This is a Password TextBox built for use with Silverlight 2 Beta 1
/// The reason this was built, is because the standard TextBox in
/// Silverlight 2 Beta 1 does not have Password support.
/// Original Link: http://pietschsoft.com/post/2008/03/PasswordTextBox-for-Silverlight-2-Beta-1.aspx
///

using System.Windows.Controls;

namespace SilverlightPasswordTextBox
{
    public partial class PasswordTextBox : TextBox
    {
        public PasswordTextBox()
        {
            this.TextChanged += new TextChangedEventHandler(PasswordTextBox_TextChanged);
            this.KeyDown += new System.Windows.Input.KeyEventHandler(PasswordTextBox_KeyDown);
        }

        #region Event Handlers

        public void PasswordTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (base.Text.Length >= _Text.Length)
                _Text += base.Text.Substring(_Text.Length);
            DisplayMaskedCharacters();
        }

        public void PasswordTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            int cursorPosition = this.SelectionStart;
            int selectionLength = this.SelectionLength;

            // Handle Delete and Backspace Keys Appropriately
            if (e.Key == System.Windows.Input.Key.Back
                || e.Key == System.Windows.Input.Key.Delete)
            {
                if (cursorPosition < _Text.Length)
                    _Text = _Text.Remove(cursorPosition, (selectionLength > 0 ? selectionLength : 1));
            }
           
            base.Text = _Text;
            this.Select((cursorPosition > _Text.Length ? _Text.Length : cursorPosition), 0);
            DisplayMaskedCharacters();
        }

        #endregion

        #region Private Methods

        private void DisplayMaskedCharacters()
        {
            int cursorPosition = this.SelectionStart;
           
            // This changes the Text property of the base TextBox class to display all Asterisks in the control
            base.Text = new string(_PasswordChar, _Text.Length);

            this.Select((cursorPosition > _Text.Length ? _Text.Length : cursorPosition), 0);
        }

        #endregion

        #region Properties

        private string _Text = string.Empty;
        /// <summary>
        /// The text associated with the control.
        /// </summary>
        public new string Text
        {
            get { return _Text; }
            set
            {
                _Text = value;
                DisplayMaskedCharacters();
            }
        }

        private char _PasswordChar = '*';
        /// <summary>
        /// Indicates the character to display for password input.
        /// </summary>
        public char PasswordChar
        {
            get { return _PasswordChar; }
            set { _PasswordChar = value; }
        }

        #endregion
    }
}

Update 4/2/2008: Here's the above code translated to VB.NET

'' Copyright 2008 Chris Pietschmann (http://pietschsoft.com)
'' This work is licensed under a Creative Commons Attribution 3.0 United States License
'' http://creativecommons.org/licenses/by/3.0/us/
''
'' This is a Password TextBox built for use with Silverlight 2 Beta 1
'' The reason this was built, is because the standard TextBox in
'' Silverlight 2 Beta 1 does not have Password support.
'' Original Link: http://pietschsoft.com/post/2008/03/PasswordTextBox-for-Silverlight-2-Beta-1.aspx
Public Class PasswordTextBox
    Inherits TextBox

    Public Sub PasswordTextBox_TextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs) Handles Me.TextChanged
        If MyBase.Text.Length >= _Text.Length Then
            _Text += MyBase.Text.Substring(_Text.Length)
        End If
        DisplayMaskedCharacters()
    End Sub

    Public Sub PasswordTextBox_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles Me.KeyDown
        Dim cursorPosition As Integer = Me.SelectionStart
        Dim selectionLength As Integer = Me.SelectionLength

        '' Handle Delete and Backspace Keys Appropriately
        If e.Key = Key.Back Or e.Key = Key.Delete Then
            If cursorPosition < _Text.Length Then
                Dim lengthToRemove As Integer = 1
                If selectionLength > 0 Then lengthToRemove = selectionLength
                _Text = _Text.Remove(cursorPosition, lengthToRemove)
            End If
        End If

        MyBase.Text = _Text
        If cursorPosition > _Text.Length Then
            Me.Select(_Text.Length, 0)
        Else
            Me.Select(cursorPosition, 0)
        End If
        DisplayMaskedCharacters()
    End Sub

    Private Sub DisplayMaskedCharacters()
        Dim cursorPosition As Integer = Me.SelectionStart

        '' This changes the Text property of the base TextBox class to display all Asterisks in the control
        MyBase.Text = New String(_PasswordChar, _Text.Length)

        If cursorPosition > _Text.Length Then
            Me.Select(_Text.Length, 0)
        Else
            Me.Select(cursorPosition, 0)
        End If
    End Sub

    Private _Text As String = String.Empty
    Overloads Property Text() As String
        Get
            Return _Text
        End Get
        Set(ByVal value As String)
            _Text = value
            DisplayMaskedCharacters()
        End Set
    End Property

    Private _PasswordChar As Char = "*"
    Public Property PasswordChar() As Char
        Get
            Return _PasswordChar
        End Get
        Set(ByVal value As Char)
            _PasswordChar = value
        End Set
    End Property

End Class

 

Currently rated 5.0 by 6 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Silverlight
Posted by crpietschmann on Friday, March 14, 2008 8:25 PM
Permalink | Comments (13) | Post RSSRSS comment feed

Related posts

Comments

Ron us

Wednesday, March 19, 2008 3:49 AM

Ron

Looks good, however, one complaint. You construct the string using a for-loop with "p += "*"", which can be inefficient. I would recommend in this case using "base.Text = new String( '*', _Text.Length )".

At first I thought you did it this way because the Silverlight runtime may have cut out that string constructor for brevity, but the Silverlight documentation claims it exists: http://msdn2.microsoft.com/en-us/library/xsa4321w(VS.95).aspx

Ron us

Wednesday, March 19, 2008 3:53 AM

Ron

One more thing. Asterisks are kind of old-school password characters. I would actually recommend using the U+2022 "Bullet" character: "••••••••••"

Looks cleaner and more professional Smile

code-inside.de

Wednesday, March 19, 2008 5:14 AM

pingback

Pingback from code-inside.de

Wöchentliche Rundablage: ASP.NET MVC, Silverlight 2, LINQ… | Code-Inside Blog

yahoo.325mb.com

Friday, March 21, 2008 6:53 PM

pingback

Pingback from yahoo.325mb.com

caret

Edson us

Wednesday, March 26, 2008 6:52 PM

Edson

i I seem to be getting this error in studio 2008
Format of the initialization string does not conform to specification starting at index 0.

while i am doing this as my connection string
<connectionStrings>
<add name="AccessFileName" connectionString="C:\Documents and Settings\Edson CTR Fernandes\My Documents\Visual Studio 2008\WebSites\CrystalReportsWebSite1\HLN_RCL.MDB" providerName="System.Data.OleDb&quot;"/>
</connectionStrings>

Nick Opris ro

Friday, March 28, 2008 10:58 PM

Nick Opris

Hi Chris,

I'm using this code in my college project.
Thank you so much for your contribution.

Jim Moore us

Thursday, April 03, 2008 7:40 AM

Jim Moore

Hi Chris,

Is it possible to write this in VB?

Thanks,
Jim

Chris Pietschmann us

Thursday, April 03, 2008 1:57 PM

Chris Pietschmann

No problem. I have posted a VB.NET version of this control within the post.

Jim Moore us

Thursday, April 03, 2008 11:10 PM

Jim Moore

Awesome! Thank you so much. I'll give it a try,
Jim

Jim Moore us

Thursday, April 03, 2008 11:13 PM

Jim Moore

Chris,

How do you wire this up? My app.xaml is loading page.xmal. page.xmal has the textbox. page.xmal.vb inherits 'UserControl', not 'TextBox'. If I create a seperate class with this code in it, how do I get the page.xmal to talk to the PasswordText.xmal when the inheritance is different? Can I place this logic directly into page.xmal? I tried this though, but then the class will only inherit either 'UserControl' or 'Textbox', but not both.

Can you help with this?

Thanks,
Jim

Rui Marinho

Friday, April 04, 2008 12:26 AM

Rui Marinho

Hi chirs.. how are you? nice post it works fine this code.

I was wondering if you now if its possible to make integreation with a login UI in silverlight and the asp autentication!

Greetings
Rui

Michael Foord us

Sunday, May 11, 2008 6:41 PM

Michael Foord

Just to let you know that (on the Mac with Safari at least), SelectionLength is broken for both the TextBox and the WatermarkedTextBox.

Smile

Michael Foord

amit kanfer il

Tuesday, May 27, 2008 2:23 PM

amit kanfer

Hi,

There was a "little" bug in the code.. here is my version (supports selection by "Home" / "End" / "Mouse" etc`)

Use as you like...

Amit.



public partial class PasswordTextBox : TextBox
{
private string text;

private const char passwordMaskChar = '*';
private int lastSelectionLength;
private int lastCursorPosition;

public new string Text
{
get { return text; }
set { text = value; }
}

public PasswordTextBox()
{
text = string.Empty;
lastSelectionLength = 0;
lastCursorPosition = 0;
this.KeyDown += PasswordTextBox_KeyDown;
this.TextChanged += PasswordTextBox_TextChanged;
this.SelectionChanged += new RoutedEventHandler(PasswordTextBox_SelectionChanged);

}

void PasswordTextBox_SelectionChanged(object sender, RoutedEventArgs e)
{

if (this.SelectionLength != lastSelectionLength)
{
lastSelectionLength = this.SelectionLength;
//Debug.WriteLine("Length = " + lastSelectionLength);
}

if (this.SelectionStart != lastCursorPosition)
{
lastCursorPosition = this.SelectionStart;
//Debug.WriteLine("Position = " + lastCursorPosition);
}

}

public void PasswordTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
//Debug.WriteLine("In PasswordTextBox_TextChanged");
if (base.Text.Length > text.Length)
{
// append some chars in a position position
for (int i = 0; i < base.Text.Length; i++)
{
if (base.Text[i] != passwordMaskChar)
{
text = text.Insert(i, base.Text[i].ToString());
}
}
}
else if (base.Text.Length == text.Length)
{
// replace an existing char
for (int i = 0; i < base.Text.Length; i++)
{
if (base.Text[i] != passwordMaskChar)
{
text = text.Substring(0, i) + base.Text[i] + text.Substring(i+1);
}
}
}
else
{
int amountOfCharsToReplace = text.Length - base.Text.Length + 1;
text = text.Substring(0, lastCursorPosition) + base.Text[lastCursorPosition] + text.Substring(lastCursorPosition + amountOfCharsToReplace);
}

//Debug.WriteLine(text);

MaskText();
}

public void PasswordTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
//Debug.WriteLine("In PasswordTextBox_KeyDown");

switch (e.Key)
{

case Key.Delete:
if (this.SelectionStart < text.Length)
{
text = text.Remove(this.SelectionStart, (lastSelectionLength > 0 ? lastSelectionLength : 1));
}
break;
case Key.Back:
if (!(lastSelectionLength == 0 && lastCursorPosition == 0))
{
text = text.Remove(this.SelectionStart, (lastSelectionLength > 0 ? lastSelectionLength : 1));
}
break;
}
return;
}

private void MaskText()
{
int cursorPosition = this.SelectionStart;

base.Text = new string(passwordMaskChar, text.Length);

this.Select((cursorPosition > text.Length ? text.Length : cursorPosition), 0);
}



}

Comments are closed

About the author

I'm Chris Pietschmann, go to the About Me page to learn more about me.

Search

Sponsors

Web.Maps.VE - ASP.NET AJAX Virtual Earth Mapping Server Control

Recent comments

Disclaimer


This work is licensed under a Creative Commons Attribution 3.0 United States License, unless explicitly stated otherwise within the posted content.
© Copyright 2004 - 2008 Chris Pietschmann