周銀輝
正如綁定TextBox控件的Text屬性一樣, 我們希望能夠將PasswordBox空間的Password屬性進行綁定, 比如在MVVM模式中,這似乎是必須的, 但可惜的是, Password屬性是不支持綁定的(不是依賴屬性, 也沒有實現INotifyPropertyChanged).
這可能是出於安全性的考慮. 但在我們的系統爲了實現View層密碼框中的密碼與後臺其它層之間的密碼屬性之間的綁定, 可以採取如下思路: 將密碼框的密碼和某一個緩衝區進行同步, 緩衝區在和後臺進行綁定. 其中密碼框與緩衝區之間的同步可採用事件進行通知, 並將緩衝區打造成依賴屬性, 然後緩衝區就支持綁定了, 並給後臺提供正確的密碼.
緩衝區可以是哈希表或其他字典結構, 以便將密碼框和緩衝區中的密碼一 一對應起來, 也可以使AttachProperty(附加屬性), 其實附加屬性的機制也就是對緩存了的一個大字典進行操作
{
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層, 如下使用便可以了:
Helpers:PasswordBoxBindingHelper.BindedPassword=
"{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
另外, 在更改了密碼框的密碼後, 需要手動更新密碼框插入符(CaretIndex)的位置, 可惜的是, 密碼框並沒有給我們提供這樣的屬性或方法(TextBox有, PasswordBox沒有), 可以採用下面的方法來設置:
{
var select = passwordBox.GetType().GetMethod("Select",
BindingFlags.Instance | BindingFlags.NonPublic);
select.Invoke(passwordBox, new object[] { start, length });
}