[WPF]实现密码框的密码绑定
周银辉 正如绑定TextBox控件的Text属性一样, 我们希望能够将PasswordBox空间的Password属性进行绑定, 比如在MVVM模式中,这似乎是必须的, 但可惜的是, Password属性是不支持绑定的(不是依赖属性, 也没有实现INotifyPropertyChanged). 这可能是出于安全性的考虑. 但在我们的系统为了实现View层密码框中的密码与后台其它层之间的密码属性之间的绑定, 可以采取如下思路: 将密码框的密码和某一个缓冲区进行同步, 缓冲区在和后台进行绑定. 其中密码框与缓冲区之间的同步可采用事件进行通知, 并将缓冲区打造成依赖属性, 然后缓冲区就支持绑定了, 并给后台提供正确的密码. 缓冲区可以是哈希表或其他字典结构, 以便将密码框和缓冲区中的密码一 一对应起来, 也可以使AttachProperty(附加属性), 其实附加属性的机制也就是对缓存了的一个大字典进行操作 public static class PasswordBoxBindingHelper { public static bool GetIsPasswordBindingEnabled(DependencyObject obj) { return ( bool )obj.GetValue(IsPasswordBindingEnabledProperty); } public static void SetIsPasswordBindingEnabled(DependencyObject obj, bool value) { obj.SetValue(IsPasswordBindingEnabledProperty, value); } public static readonly DependencyProperty IsPasswordBindingEnabledProperty = DependencyProperty.RegisterAttached( " IsPasswordBindingEnabled " , typeof ( bool ), typeof (PasswordBoxBindingHelper), new UIPropertyMetadata( false , OnIsPasswordBindingEnabledChanged)); private static void OnIsPasswordBindingEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as PasswordBox; if (passwordBox != null ) { passwordBox.PasswordChanged -= PasswordBoxPasswordChanged; if (( bool )e.NewValue) { passwordBox.PasswordChanged += PasswordBoxPasswordChanged; } } } // when the passwordBox's password changed, update the buffer static void PasswordBoxPasswordChanged( object sender, RoutedEventArgs e) { var passwordBox = (PasswordBox) sender; if ( ! String.Equals(GetBindedPassword(passwordBox),passwordBox.Password)) { SetBindedPassword(passwordBox, passwordBox.Password); } } public static string GetBindedPassword(DependencyObject obj) { return ( string )obj.GetValue(BindedPasswordProperty); } public static void SetBindedPassword(DependencyObject obj, string value) { obj.SetValue(BindedPasswordProperty, value); } public static readonly DependencyProperty BindedPasswordProperty = DependencyProperty.RegisterAttached( " BindedPassword " , typeof ( string ), typeof (PasswordBoxBindingHelper), new UIPropertyMetadata( string .Empty, OnBindedPasswordChanged)); // when the buffer changed, upate the passwordBox's password private static void OnBindedPasswordChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as PasswordBox; if (passwordBox != null ) { passwordBox.Password = e.NewValue == null ? string .Empty : e.NewValue.ToString(); } } }
在View层, 如下使用便可以了: < PasswordBox Helpers:PasswordBoxBindingHelper.IsPasswordBindingEnabled ="True" Helpers:PasswordBoxBindingHelper.BindedPassword = " {Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} " />
另外, 在更改了密码框的密码后, 需要手动更新密码框插入符(CaretIndex)的位置, 可惜的是, 密码框并没有给我们提供这样的属性或方法(TextBox有, PasswordBox没有), 可以采用下面的方法来设置: private static void SetPasswordBoxSelection(PasswordBox passwordBox, int start, int length) { var select = passwordBox.GetType().GetMethod( " Select " , BindingFlags.Instance | BindingFlags.NonPublic); select.Invoke(passwordBox, new object [] { start, length }); }