Wpf的密码框PasswordBox有一个属性叫SecurePassword,它不是依赖属性,无法绑定。
出于安全考虑,你永远不要将明文密码保存在内存中,所以就不要想如何如何绑定到SecurePassword啦。
当然,非要绑定还是有办法的,添加两个附加属性就好了,方法你可以自行百度~这不是我关心的重点~
今天主要实现一个Password样式,和获取明文密码的功能。
效果图:
tip:输入1234后点击查看密码弹出明文密码
下面是代码过程~
1。要想实现水印功能,要监听密码属性,可是密码不是依赖属性无法根据它确定是否有密码。但是password自身有一个PasswordChanged事件,这个事件可以监听到密码改变。于是,添加一个附加监听属性和一个是否有密码属性,注册PasswordChanged事件,就可以确定是否有密码了~进而样式里面就可以绑定到是否有密码这个属性上了~
属性如下 :
添加一个PasswordAttachedProperty.cs,里面定义两个附加属性
namespace WpfTemplate
{
public class MonitorPasswordProperty : BaseAttachedProperty<MonitorPasswordProperty, bool>
{
public override void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var passwordBox = sender as PasswordBox;
if (passwordBox == null) return;
passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;
if ((bool)e.NewValue)
{
HasTextProperty.SetValue(passwordBox, passwordBox.SecurePassword.Length > 0);
passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
}
}
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
HasTextProperty.SetValue((PasswordBox)sender);
}
}
public class HasTextProperty : BaseAttachedProperty<HasTextProperty, bool>
{
public static void SetValue(DependencyObject sender)
{
SetValue(sender, ((PasswordBox)sender).SecurePassword.Length > 0);
}
}
}
文中BaseAttachedProperty 类声明 可参见
2。基于这两个附加属性,开始编写样式
<Style TargetType="{x:Type PasswordBox}" x:Key="password">
<Setter Property="FontSize" Value="{StaticResource FontSizeLarge}" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="0 5 0 5" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="BorderThickness" Value="0 0 0 1" />
<Setter Property="CaretBrush" Value="White"/>
<Setter Property="local:MonitorPasswordProperty.Value" Value="True" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<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">
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<TextBlock IsHitTestVisible="False"
Text="{TemplateBinding Tag}"
x:Name="placeholder"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
Padding="{TemplateBinding Padding}"
Visibility="{TemplateBinding local:HasTextProperty.Value, Converter={local:BooleanToVisiblityConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Foreground="Gray"
>
</TextBlock>
</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="#FF7EB4EA"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="#FF569DE5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这样水印功能就开发完了~
3。获取 密码功能。
passwordbox的没有Password属性,只有一个SecurePassword,它 是SecureString类型,要获取密码就要先获取这个东西。
在mvvm模式下,没有绑定,viewmodel如何得到这个属性呢,
实现一个IHavePassword接口给MainWindow实现,里面有一个SecurePassword,具体如下 :
public interface IHavePassword
{
SecureString SecurePassword { get; }
}
将SecureString转成String
给SecureString类添加一个扩展方法:
public static class SecureStringHelpers
{
public static string Unsecure(this SecureString securePassword)
{
if (securePassword == null) return string.Empty;
var unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
}
这样的话就可以直接像pass.Unsecure()这样获取明文啦
mainwindow实现接口后代码如下 :
public partial class MainWindow : Window,IHavePassword
{
public MainWindow()
{
InitializeComponent(); ;
DataContext = new MainWindowViewModel(this);
}
public SecureString SecurePassword => PasswordText?.SecurePassword;
}
2.MainWindowViewModel内容如下
public class MainWindowViewModel:BaseViewModel
{
private Window mWindow;//window 对象
public bool ButtonIsBusy { get; set; }
public ICommand MinimizeCommand { get; set; }
public ICommand MaximizeCommand { get; set; }
public ICommand CloseCommand { get; set; }
public ICommand BusyCommand { get; set; }
//获取密码Command
public ICommand GetPasswordCommand { get; set; }
#region constructor
public MainWindowViewModel(Window window)
{
mWindow = window;
MinimizeCommand = new RelayCommand(() => mWindow.WindowState = WindowState.Minimized);
MaximizeCommand = new RelayCommand(() => mWindow.WindowState ^= WindowState.Maximized);
CloseCommand = new RelayCommand(() => mWindow.Close());
BusyCommand = new RelayCommand(() => ButtonIsBusy = !ButtonIsBusy);
//初始化command
GetPasswordCommand = new RelayCommand(() => MessageBox.Show("输入的密码是 "+(mWindow as IHavePassword).SecurePassword.Unsecure()));
}
#endregion
}
下面在MainWindow.xaml里面引用方法如下 :
<Grid Background="#1E1E1E">
<WrapPanel Margin="10">
<PasswordBox Width="150"
Tag="请输入密码"
x:Name="PasswordText"
Style="{StaticResource password}"/>
<Button Content="查看密码" Style="{StaticResource TextRectButton}"
Foreground="White"
BorderBrush="White"
Command="{Binding GetPasswordCommand}"/>
</WrapPanel>
</Grid>
大功告成啦哈哈哈哈哈哈咯~
暂无评论内容