WPF PasswordBox的数据绑定功能处理

当我们输入的敏感信息时,用到最多的就是使用PasswordBox。但是由于某些原因或考虑,wpf的标准并不支持Binding方法。PasswordBox的属性只是一个普通的CLR属性,并不是Dependency 属性。

幸运的是,wpf具有附加属性的概念,允许我们更加容易的进行控件的扩展。下面就使用附加属性进行处理PasswordBox的绑定功能

使用方法如下

<Page xmlns:ff="clr-namespace:FunctionalFun.UI">
  <!-- [Snip] -->
  <PasswordBox x:Name="PasswordBox"
      ff:PasswordBoxAssistant.BindPassword="true"  ff:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</Page>

设定BindPassword属性为True,这样代码就会在PasswordBox上侦听PasswordChanged事件,只要当PasswordBox的内容有更改,代码就会把更改的新的值推送到附加属性:BoundPassword中,然后把要绑定的值绑定到BoundPassword中。唯一复杂的就是要确保整个事件不会递归和UpdatingPassword私有属性

using System.Windows;
using System.Windows.Controls;
 
namespace FunctionalFun.UI
{
  public static class PasswordBoxAssistant
  {
      public static readonly DependencyProperty BoundPassword =
          DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
 
      public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
          "BindPassword", typeof (bool), typeof (PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));
 
      private static readonly DependencyProperty UpdatingPassword =
          DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false));
 
      private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
          PasswordBox box = d as PasswordBox;
 
          // only handle this event when the property is attached to a PasswordBox
          // and when the BindPassword attached property has been set to true
          if (d == null || !GetBindPassword(d))
          {
              return;
          }
 
          // avoid recursive updating by ignoring the box's changed event
          box.PasswordChanged -= HandlePasswordChanged;
 
          string newPassword = (string)e.NewValue;
 
          if (!GetUpdatingPassword(box))
          {
              box.Password = newPassword;
          }
 
          box.PasswordChanged += HandlePasswordChanged;
      }
 
      private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
      {
          // when the BindPassword attached property is set on a PasswordBox,
          // start listening to its PasswordChanged event
 
          PasswordBox box = dp as PasswordBox;
 
          if (box == null)
          {
              return;
          }
 
          bool wasBound = (bool)(e.OldValue);
          bool needToBind = (bool)(e.NewValue);
 
          if (wasBound)
          {
              box.PasswordChanged -= HandlePasswordChanged;
          }
 
          if (needToBind)
          {
              box.PasswordChanged += HandlePasswordChanged;
          }
      }
 
      private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
      {
          PasswordBox box = sender as PasswordBox;
 
          // set a flag to indicate that we're updating the password
          SetUpdatingPassword(box, true);
          // push the new password into the BoundPassword property
          SetBoundPassword(box, box.Password);
          SetUpdatingPassword(box, false);
      }
 
      public static void SetBindPassword(DependencyObject dp, bool value)
      {
          dp.SetValue(BindPassword, value);
      }
 
      public static bool GetBindPassword(DependencyObject dp)
      {
          return (bool)dp.GetValue(BindPassword);
      }
 
      public static string GetBoundPassword(DependencyObject dp)
      {
          return (string)dp.GetValue(BoundPassword);
      }
 
      public static void SetBoundPassword(DependencyObject dp, string value)
      {
          dp.SetValue(BoundPassword, value);
      }
 
      private static bool GetUpdatingPassword(DependencyObject dp)
      {
          return (bool)dp.GetValue(UpdatingPassword);
      }
 
      private static void SetUpdatingPassword(DependencyObject dp, bool value)
      {
          dp.SetValue(UpdatingPassword, value);
      }
  }
}

原文 


在MVVM模式下,PassWordBox的密码不能直接绑定到ViewModel的属性,因为密码是敏感信息,不应该以明文形式存储在内存中。因此,我们需要使用PasswordBox的SecureString属性来存储密码,并在ViewModel中创建一个SecureString类型的属性来接收密码。 首先,在XAML中,我们需要将PassWordBoxPasswordChanged事件与Command绑定,以便在密码发生变化时触发Command执行。例如: ``` <PasswordBox PasswordChanged="{Binding PasswordChangedCommand}" /> ``` 然后,在ViewModel中,我们需要创建一个SecureString类型的属性来接收密码,并创建一个Command来处理密码变化事件,例如: ``` public class LoginViewModel : INotifyPropertyChanged { private SecureString _securePassword; public SecureString SecurePassword { get { return _securePassword; } set { _securePassword = value; OnPropertyChanged(nameof(SecurePassword)); } } public ICommand PasswordChangedCommand => new RelayCommand<PasswordBox>((pb) => { SecurePassword = pb.SecurePassword; }); // INotifyPropertyChanged implementation... } ``` 在这个示例中,我们创建了一个SecurePassword属性来接收密码,并使用PasswordBox的SecurePassword属性将密码赋值给SecurePassword。我们还创建了一个PasswordChangedCommand来处理密码变化事件,该Command使用RelayCommand实现,并将PasswordBox作为参数传递。当密码发生变化时,Command会将SecurePassword属性设置为新密码。 需要注意的是,由于SecureString无法直接转换为字符串,因此我们需要在处理密码时使用相应的方法来转换或处理SecureString。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值