// The .NET Frasmwork adds this style bit to the TextBox.
private const int WS_MAXIMIZEBOX = 0x00010000;
// This is the style flag that makes a text box a real password box.
private const int ES_PASSWORD = 0x0020;
private const int ES_AUTOHSCROLL = 0x0080;
/// <summary>
/// Used in ProcessKeyMessage
/// </summary>
private const int WM_CHAR = 0x0102;
#endregion
// An internal buffer used to hold the text of the
// password being entered
// We don't hold the password in the .Text member of TextBox
// since it used in the window text.
private System.Text.StringBuilder _internalBuffer
= new System.Text.StringBuilder();
// Default constructor of PasswordBox
public PasswordBox()
{
// No further initialization required
}
// Multiline password aren't allowed wo be just hide the implementation
private new bool Multiline
{
get { return false; }
}
// Sets/gets the actual password entered
[Localizable(false)]
public override string Text
{
get { return _internalBuffer.ToString(); }
set
{
//assign base.Text first
base.Text = ((value == null) ? value : new String(' ', value.Length));
// Not fill the buffer with the new value
_internalBuffer = new System.Text.StringBuilder(value, MaxLength);
Debug.Assert(base.TextLength == _internalBuffer.Length);
}
}
// Override. TextLength returns the length of the internal buffer.
// TextLength is overridden so that checks can be made
// during debugging to ensure the lengths of base.Text
// and _internalsBuffer.Lengh are equal.
public override int TextLength
{
get
{
Debug.Assert(base.TextLength == _internalBuffer.Length,
"base.TextLength != _internalBuffer.Length");
return _internalBuffer.Length;
}
}
// Overridden. See Control.CreateParams
// This is how we get PasswordBox to show the black dots instead
// of PasswordChar on systems that support it.
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
if ( !DesignMode )
{
// Even tho the style is added here, it seems
// to be removed somewhere. What makes things
// stranger is, setting this style does have
// an effect, and does cause the TextBox to
// work as expected.
cp.Style |= ES_PASSWORD;
}
return cp;
}
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
}
base.Dispose( disposing );
}
// Overridden. Processes a command key.
// A Message, passed by reference, that represents the window message to process.
// One of the Keys values that represents the key to process.
// true if the character was processed by the control; otherwise, false
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if( (keyData == (Keys.Control | Keys.V))
|| (keyData == (Keys.Shift | Keys.Insert)) )
{
//Do the paste if appropriate
IDataObject data = Clipboard.GetDataObject();
if ( data.GetDataPresent(DataFormats.Text) )
{
ReplaceSelection((string)data.GetData(DataFormats.Text));
return true;
}
}
else if ( keyData == (Keys.Control | Keys.C)
|| keyData == (Keys.Control | Keys.Insert)
|| keyData == (Keys.Shift | Keys.Delete) )
{
// Eat the keystroke
return true;
}
else if ( keyData == Keys.Delete )
{
// Process the delete key at the current position
DeleteChar();
}
return base.ProcessCmdKey(ref msg, keyData);
}
// Overridden. Processes a keyboard message. See online documentation
// A Message, passed by reference, that represents the window message to process.
// true if the message was processed by the control; otherwise, false.
protected override bool ProcessKeyMessage(ref Message m)
{
bool result = true;
switch ( m.Msg )
{
// This should be the only one we have to handle
case WM_CHAR:
{
switch ((Keys)(int)m.WParam)
{
case Keys.Back:
ProcessChar('\b');
break;
/*
* If there are any problems you may
* want to add these as needed.
*************************************
* case Keys.LineFeed:
* break;
* case Keys.Escape:
* break;
*
* case Keys.Tab:
* break;
*
* case Keys.Enter:
* break;
*
*/
default:
char c = (char)m.WParam;
if ( !char.IsControl(c) )
{
m.WParam = (IntPtr)' ';
ProcessChar(c);
}
break;
}
break;
}
default:
break;
}
// On with default handling
result = ProcessKeyEventArgs(ref m);
return result;
}
#region ** Internal Helper Methods **
/// <summary>
/// Deletes the character(s) at the current position
/// </summary>
private void DeleteChar()
{
int posStart = SelectionStart;
int posLength = SelectionLength;
if ( posLength > 0 )
{
_internalBuffer.Remove(posStart, posLength);
}
else
{
if ( posStart < (_internalBuffer.Length -1) )
{
_internalBuffer.Remove(posStart, 1);
}
}
}
/// <summary>
/// Replaces the current selection with string s
/// </summary>
/// <param name="s">The string to use as the replacement.</param>
private void ReplaceSelection(string s)
{
int posStart = SelectionStart;
int posLength = SelectionLength;
if ( posLength > 0 )
{
_internalBuffer.Remove(posStart, posLength);
}
Text = _internalBuffer.Insert(posStart, s).ToString();
Select(posStart +s.Length, 0);
}
/// <summary>
/// Process a character and ake the appropriate action.
/// </summary>
/// <param name="c">
/// The character to process. If char c is not '\b' then char c
/// is inserted at the current position.
/// </param>
private void ProcessChar(char c)
{
int posStart = SelectionStart;
int posLength = SelectionLength;
if ( posLength > 0 )
{
_internalBuffer.Remove(posStart, posLength);
}
else
{
if ( c == '\b' )
{
if ( posStart > 0 )
{
_internalBuffer.Remove(posStart -1, 1);
}
return;
}
}
_internalBuffer.Insert(posStart, c);
}
#endregion
}