天天看點

[WPF]實作密碼框的密碼綁定

原文:

[WPF]實作密碼框的密碼綁定

                                                 [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), 

            new UIPropertyMetadata(string.Empty, OnBindedPasswordChanged));

        //when the buffer changed, upate the passwordBox's password

        private static void OnBindedPasswordChanged(DependencyObject obj, 

                                                    DependencyPropertyChangedEventArgs e)

            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 });