Put a textbox on top of the password box, and then use a little databinding and animation. This chunk of XAML will allow the textbox to be visible as long as there is typing going on, but as soon as the typing stops, the textbox will fade away, leaving only the password box with the password characters showing.
<Window.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="textBox">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="TextBoxBase.TextChanged" SourceName="textBox">
<StopStoryboard BeginStoryboardName="Storyboard1_BeginStoryboard"/>
<BeginStoryboard x:Name="Storyboard1_BeginStoryboard" Storyboard="{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<PasswordBox x:Name="passwordBox"/>
<TextBox x:Name="textBox"
Text="{Binding ElementName=passwordBox, Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Opacity="100"/>
You can play around with the KeyTimes in the animation to get the delay that you prefer. You can also change the font settings in the textbox to get the typed text and the password characters to line up better.
EDIT
If you want to only display the last character typed as clear text:
This situation is a little different and requires some more complexity. this scenario uses only a textbox on the window, not the passwordbox.
<TextBox Name="tbxPwd" Margin="20,0"
Text="{Binding Path=DisplayedPwd}" />
In your code-behind for the window (or in your ViewModel class) you will need two properties, ActualPwd
and DisplayedPwd
. The textbox is bound to the DisplayedPwd
property.
In the code-behind, you will need the following code:
Private Sub tbxPwd_PreviewKeyDown(sender As Object, e As System.Windows.Input.KeyEventArgs) _
Handles tbxPwd.PreviewKeyDown
If e.Key = Key.Back Then
If ActualPwd.Length > 0 Then
//Remove the last character.
ActualPwd = ActualPwd.Substring(0, ActualPwd.Length - 1)
ShowLastCharacter()
tbxPwd.CaretIndex = DisplayedPwd.Length
End If
End If
End Sub
Private Sub tbxPwd_PreviewTextInput(sender As Object, e As System.Windows.Input.TextCompositionEventArgs) _
Handles tbxPwd.PreviewTextInput
ActualPwd &= e.Text
e.Handled = True
ShowLastCharacter()
tbxPwd.CaretIndex = DisplayedPwd.Length
End Sub
Private Sub ShowLastCharacter()
Dim lastChar As Char = ActualPwd.Substring(ActualPwd.Length - 1)
//Reset the displayed pwd.
DisplayedPwd = ""
For i As Int32 = 0 To ActualPwd.Length - 2
DisplayedPwd &= "?"
Next
DisplayedPwd &= lastChar
End Sub
The tbxPwd_PreviewTextInput method is used to retrieve the character that is typed by the user. The tbxPwd_PreviewKeyDown method is used to retrieve the BackSpace key, or any other control character key you want to detect.
There is no delay in this code, so it always displays the last character of the password string in clear text. It should be easy enough to add some code along with a Timer to change the last character to the pwd character after some delay.
The above code hasn't been thoroughly debugged, so there may be issues if the user backspaces out their entire password to start over.
Tip: Alt+0149 displays the 'bullet' password character.