Recently, a
question that pops up to me “How do I implement a functionality to show
password in PasswordBox like windows 8 login screen in WPF?”
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="RevealButtonExtendedStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border x:Name="PasswordRevealGlyphBorder" Background="Transparent" Margin="0,1"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock x:Name="GlyphElement" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Center"
Text="" FontFamily="Segoe UI Symbol" Margin="3,0"
FontSize="{TemplateBinding FontSize}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=GlyphElement, Path=IsMouseOver}" Value="True">
<Setter TargetName="PasswordRevealGlyphBorder" Property="Background"
Value="Gainsboro" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsPressed}"
Value="True">
<Setter TargetName="PasswordRevealGlyphBorder" Property="Background" Value="Black" />
<Setter TargetName="GlyphElement" Property="Foreground" Value="White" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource {x:Type PasswordBox}}">
<Setter Property="PasswordChar" Value="●"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Grid>
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBox x:Name="RevealedPassword" IsReadOnly="True"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
VerticalContentAlignment="Center"
Padding="{TemplateBinding Padding}"
Margin="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Visibility="Hidden" BorderThickness="0" />
<Button x:Name="PART_RevealButton"
Grid.Column="1" SnapsToDevicePixels="True"
Style="{StaticResource RevealButtonExtendedStyle}" Visibility="Visible">
</Button>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
<DataTrigger Binding="{Binding ElementName=PART_RevealButton, Path=IsPressed}" Value="True">
<Setter TargetName="RevealedPassword" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=RevealedPassword, Path=Text.Length}" Value="0">
<Setter TargetName="PART_RevealButton" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
The style can be default style for PasswordBox control or can be keyed resource.
Second point here is to subscribe the PasswordChanged event for PasswordBox control. Whenever there is a change in password, it pushes the new value into the textbox “RevealedPassword” (defined in template).
Now, clicking on “PART_RevealButton” will displays the password entered.
The PasswordBox
control is a special type of TextBox designed to enter passwords. It shields
the char entered by user by showing the char set for PasswordChar dependency property.
PasswordChar property can set to any char as required (default is ●).
While doing
search for reference over internet, I found this article by author DotNetMastermind
which implements a “Smart Login Overlay WPF Control“. So taking reference
from it, I have implemented following code to demonstrate “how to show password
in PasswordBox like windows 8 login screen”.
Following
things has been done
- Overriding the style of PasswordBox
- . Subscribe for password PasswordChanged event
Overriding the Style for PasswordBox
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="RevealButtonExtendedStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border x:Name="PasswordRevealGlyphBorder" Background="Transparent" Margin="0,1"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock x:Name="GlyphElement" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Center"
Text="" FontFamily="Segoe UI Symbol" Margin="3,0"
FontSize="{TemplateBinding FontSize}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=GlyphElement, Path=IsMouseOver}" Value="True">
<Setter TargetName="PasswordRevealGlyphBorder" Property="Background"
Value="Gainsboro" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsPressed}"
Value="True">
<Setter TargetName="PasswordRevealGlyphBorder" Property="Background" Value="Black" />
<Setter TargetName="GlyphElement" Property="Foreground" Value="White" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource {x:Type PasswordBox}}">
<Setter Property="PasswordChar" Value="●"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Grid>
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBox x:Name="RevealedPassword" IsReadOnly="True"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
VerticalContentAlignment="Center"
Padding="{TemplateBinding Padding}"
Margin="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Visibility="Hidden" BorderThickness="0" />
<Button x:Name="PART_RevealButton"
Grid.Column="1" SnapsToDevicePixels="True"
Style="{StaticResource RevealButtonExtendedStyle}" Visibility="Visible">
</Button>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
<DataTrigger Binding="{Binding ElementName=PART_RevealButton, Path=IsPressed}" Value="True">
<Setter TargetName="RevealedPassword" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=RevealedPassword, Path=Text.Length}" Value="0">
<Setter TargetName="PART_RevealButton" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
Second point here is to subscribe the PasswordChanged event for PasswordBox control. Whenever there is a change in password, it pushes the new value into the textbox “RevealedPassword” (defined in template).
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
var passwordBox = (PasswordBox)e.Source;
if (passwordBox != null)
{
System.Diagnostics.Debug.WriteLine(passwordBox.Password);
var textBox = passwordBox.Template.FindName("RevealedPassword",
passwordBox) as TextBox;
if (textBox != null)
{
textBox.Text =
passwordBox.Password;
}
}
}
Now, clicking on “PART_RevealButton” will displays the password entered.
The code can be downloaded from here.
No comments:
Post a Comment