WPF PasswordBox 明文顯示的樣式


最近學習WPF,突然想做PasswordBox明文顯示的樣式,在網上搜索了一下,代碼都有問題,不能夠直接復用。所以,在同事的幫助下,做了一個明文顯示樣式的Demo。

 

首先,創建一個WPF App的項目。

打開MainWindow.xaml文件,代碼如下:

 1 <Window x:Class="WpfApp4.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:WpfApp4"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="450" Width="800">
 9     <Grid>
10     </Grid>
11 </Window>
View Code

構建Grid布局,並創建兩個控件,分別為TextBox、PasswordBox,代碼如下:

1 <Grid>
2         <Grid.RowDefinitions>
3             <RowDefinition Height="40"/>
4             <RowDefinition Height="auto"/>
5         </Grid.RowDefinitions>
6         <TextBox x:Name="userName" Grid.Row="0" Width="200" Height="40" HorizontalAlignment="Left"></TextBox>
7         <PasswordBox x:Name="userPwd" Grid.Row="1" Width="200" Height="40" HorizontalAlignment="Left" Style="{StaticResource PasswordBoxStyle1}" FontSize="20" VerticalAlignment="Center" local:ControlAttachProperty.PlaceHolder="請輸入密碼" />
8     </Grid>
View Code

此時,Style="{StaticResource PasswordBoxStyle1}" 與 local:ControlAttachProperty.PlaceHolder="請輸入密碼" 會報錯。(現在可以刪掉這兩句)

 

現在要實現的樣式效果:

1、輸入密碼后,點擊眼睛按鈕可以顯示密碼明文效果。

2、密碼框為空且沒有獲取焦點時,顯示提示文字。

3、密碼為空時,不允許點擊眼睛按鈕

樣式代碼需要放在Window標簽下Grid標簽前,代碼如下:

  1     <Window.Resources>
  2         <Style x:Key="FocusVisual">
  3             <Setter Property="Control.Template">
  4                 <Setter.Value>
  5                     <ControlTemplate>
  6                         <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
  7                     </ControlTemplate>
  8                 </Setter.Value>
  9             </Setter>
 10         </Style>
 11         
 12         <!--眼睛按鈕的樣式-->
 13         <Style TargetType="Button" x:Key="EyeButton">
 14             <Setter Property="Template">
 15                 <Setter.Value>
 16                     <ControlTemplate TargetType="Button">
 17                         <Border Background="{TemplateBinding Background}" />
 18                     </ControlTemplate>
 19                 </Setter.Value>
 20             </Setter>
 21         </Style>
 22         
 23         <!--PassWordBox樣式-->
 24         <SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
 25         <SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
 26         <SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
 27         <Style x:Key="PasswordBoxStyle1" TargetType="{x:Type PasswordBox}">
 28             <Setter Property="local:PasswordBoxHelper.Attach" Value="True"/>
 29             <Setter Property="PasswordChar" Value="●"/>
 30             <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
 31             <Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
 32             <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
 33             <Setter Property="BorderThickness" Value="1"/>
 34             <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
 35             <Setter Property="HorizontalContentAlignment" Value="Left"/>
 36             <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
 37             <Setter Property="AllowDrop" Value="true"/>
 38             <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
 39             <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
 40             <Setter Property="Template">
 41                 <Setter.Value>
 42                     <ControlTemplate TargetType="{x:Type PasswordBox}">
 43                         <Border x:Name="border" CornerRadius="10" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
 44                             <!--重寫構造PasswordBox-->
 45                             <Grid x:Name="PART_InnerGrid">
 46                                 <Grid.ColumnDefinitions>
 47                                     <ColumnDefinition/>
 48                                     <ColumnDefinition Width="Auto"/>
 49                                 </Grid.ColumnDefinitions>
 50                                 <!--PasswordBox原有的顯示節點-->
 51                                 <ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" IsTabStop="False" VerticalAlignment="Stretch" Background="{x:Null}" VerticalContentAlignment="Center" Margin="5,5"/>
 52                                 <!--創建明文顯示的TextBox-->
 53                                 <TextBox x:Name="PART_PasswordShower"  BorderBrush="Transparent" Text="{Binding Path=(local:PasswordBoxHelper.Password),RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="0" Visibility="Collapsed" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,5"/>
 54                                 <!--創建提示字符-->
 55                                 <TextBlock x:Name="PART_PlaceHolder" Text="{Binding Path=(local:ControlAttachProperty.PlaceHolder),RelativeSource={RelativeSource TemplatedParent}}"  Visibility="Collapsed" Opacity="0.6" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5,5"/>
 56                                 <!--觸發按鈕顯示樣式-->
 57                                 <Button x:Name="PART_ToggleEye" Grid.Column="1" Width="40"  Margin="3,3" BorderThickness="0" Style="{StaticResource EyeButton}" >
 58                                     <Button.Background>
 59                                         <ImageBrush x:Name="img_eye" ImageSource="eye_slash.png"/>
 60                                     </Button.Background>
 61                                 </Button>
 62                             </Grid>
 63                         </Border>
 64                         <ControlTemplate.Triggers>
 65                             <Trigger Property="IsEnabled" Value="false">
 66                                 <Setter Property="Opacity" TargetName="border" Value="0.56"/>
 67                             </Trigger>
 68                             <Trigger Property="IsMouseOver" Value="true">
 69                                 <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
 70                             </Trigger>
 71                             <Trigger Property="IsKeyboardFocused" Value="true">
 72                                 <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
 73                             </Trigger>
 74                             <!--密碼框為空設置按鈕禁用-->
 75                             <Trigger Property="local:PasswordBoxHelper.Password"  Value="">
 76                                 <Setter TargetName="PART_ToggleEye" Property="IsEnabled" Value="False"/>
 77                             </Trigger>
 78                             <!--按住按鈕,更改按鈕背景圖片並設置明文框顯示且密碼框不顯示且不占用-->
 79                             <Trigger Property="IsPressed" SourceName="PART_ToggleEye" Value="true">
 80                                 <Setter TargetName="PART_ToggleEye" Property="Background">
 81                                     <Setter.Value>
 82                                         <ImageBrush ImageSource="eye.png"/>
 83                                     </Setter.Value>
 84                                 </Setter>
 85                                 <Setter TargetName="PART_ContentHost" Property="Visibility" Value="Collapsed"/>
 86                                 <Setter TargetName="PART_PasswordShower" Property="Visibility" Value="Visible"/>
 87                             </Trigger>
 88                             <!--密碼框為空不且沒有獲取焦點時,設置提示文字顯示-->
 89                             <MultiTrigger>
 90                                 <MultiTrigger.Conditions>
 91                                     <Condition Property="local:PasswordBoxHelper.Password"  Value=""/>
 92                                     <Condition Property="IsFocused" Value="False"/>
 93                                 </MultiTrigger.Conditions>
 94                                 <Setter TargetName="PART_PlaceHolder" Property="Visibility" Value="Visible"/>
 95                             </MultiTrigger>
 96                         </ControlTemplate.Triggers>
 97                     </ControlTemplate>
 98                 </Setter.Value>
 99             </Setter>
100             <Style.Triggers>
101                 <MultiTrigger>
102                     <MultiTrigger.Conditions>
103                         <Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
104                         <Condition Property="IsSelectionActive" Value="false"/>
105                     </MultiTrigger.Conditions>
106                     <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
107                 </MultiTrigger>
108             </Style.Triggers>
109         </Style>
110     </Window.Resources>
View Code

代碼中使用了PasswordBoxHelper及ControlAttachProperty的類,PasswordBoxHelper用於獲取PasswordwordBox的密碼,提供給顯示框顯示明文密碼。ControlAttachProperty用於創建提示文字的依賴屬性。(注意:兩個類放在MainWindow.xaml同級目錄中)

 

PasswordBoxHelper代碼如下:

 1 public class PasswordBoxHelper
 2     {
 3         public static readonly DependencyProperty PasswordProperty =
 4             DependencyProperty.RegisterAttached("Password",
 5             typeof(string), typeof(PasswordBoxHelper),
 6             new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));
 7         public static readonly DependencyProperty AttachProperty =
 8             DependencyProperty.RegisterAttached("Attach",
 9             typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, Attach));
10         private static readonly DependencyProperty IsUpdatingProperty =
11            DependencyProperty.RegisterAttached("IsUpdating", typeof(bool),
12            typeof(PasswordBoxHelper));
13 
14         public static void SetAttach(DependencyObject dp, bool value)
15         {
16             dp.SetValue(AttachProperty, value);
17         }
18         public static bool GetAttach(DependencyObject dp)
19         {
20             return (bool)dp.GetValue(AttachProperty);
21         }
22         public static string GetPassword(DependencyObject dp)
23         {
24             return (string)dp.GetValue(PasswordProperty);
25         }
26         public static void SetPassword(DependencyObject dp, string value)
27         {
28             dp.SetValue(PasswordProperty, value);
29         }
30         private static bool GetIsUpdating(DependencyObject dp)
31         {
32             return (bool)dp.GetValue(IsUpdatingProperty);
33         }
34         private static void SetIsUpdating(DependencyObject dp, bool value)
35         {
36             dp.SetValue(IsUpdatingProperty, value);
37         }
38         private static void OnPasswordPropertyChanged(DependencyObject sender,
39             DependencyPropertyChangedEventArgs e)
40         {
41             PasswordBox passwordBox = sender as PasswordBox;
42             passwordBox.PasswordChanged -= PasswordChanged;
43             if (!(bool)GetIsUpdating(passwordBox))
44             {
45                 passwordBox.Password = (string)e.NewValue;
46             }
47             passwordBox.PasswordChanged += PasswordChanged;
48         }
49         private static void Attach(DependencyObject sender,
50             DependencyPropertyChangedEventArgs e)
51         {
52             PasswordBox passwordBox = sender as PasswordBox;
53             if (passwordBox == null)
54                 return;
55             if ((bool)e.OldValue)
56             {
57                 passwordBox.PasswordChanged -= PasswordChanged;
58             }
59             if ((bool)e.NewValue)
60             {
61                 passwordBox.PasswordChanged += PasswordChanged;
62             }
63         }
64         private static void PasswordChanged(object sender, RoutedEventArgs e)
65         {
66             PasswordBox passwordBox = sender as PasswordBox;
67             SetIsUpdating(passwordBox, true);
68             SetPassword(passwordBox, passwordBox.Password);
69             SetIsUpdating(passwordBox, false);
70         }
71     }
View Code

ControlAttachProperty代碼如下:

 1 public class ControlAttachProperty
 2     {
 3         public static string GetPlaceHolder(DependencyObject obj)
 4         {
 5             return (string)obj.GetValue(PlaceHolderProperty);
 6         }
 7 
 8         public static void SetPlaceHolder(DependencyObject obj, string value)
 9         {
10             obj.SetValue(PlaceHolderProperty, value);
11         }
12 
13         // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
14         public static readonly DependencyProperty PlaceHolderProperty =
15             DependencyProperty.RegisterAttached("PlaceHolder", typeof(string), typeof(ControlAttachProperty), new PropertyMetadata(string.Empty));
16     }
View Code

現在,需要把之前刪掉的兩句(Style="{StaticResource PasswordBoxStyle1}" 與 local:ControlAttachProperty.PlaceHolder="請輸入密碼" )加進來。 Style是設置PasswordBox的樣式, 在樣式里可以重構PasswordBox。local:ControlAttachProperty.PlaceHolder是為passwordbox新增的依賴屬性。

運行代碼即可獲取實現的效果。

需要注意的是:

①代碼中用了兩個圖片,分別時eye.png與eye_slash.png, 在寫Demo的時候,是直接放在MainWindow.xaml同級文件夾里。

②xmlns:local="clr-namespace:WpfApp4" , 這里是創建wpf項目的命名空間,喜歡復制代碼的兄弟,記得更改為當前創建項目的命名空間。

代碼下載:密碼明文顯示/隱藏


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM