Search This Blog

Sunday, October 11, 2015

WPF : Show password in PasswordBox like windows 8 login screen

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?”
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
  1.         Overriding the style of PasswordBox
  2.       . 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="&#xE052;" 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).


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