在MVVM中使用PasswordBox控件,碰到一个问题。由于**PasswordBox.Password**属性并不是一个依赖属性,所以无法将其作为Binding的目标。
# 使用附加属性的解决方案
![Password Demo.gif](http://upload-images.jianshu.io/upload_images/140233-dbd415eb4cf9aeb2.gif)
**思路:**定义两个依赖属性**Attach**和**AttachPassoword**
Attatch为True时,给PasswordBox的PasswordChanged事件添加一个订阅者。在这个订阅者中,利用AttachPassword的Set包装器将PasswordBox.Password赋值给这个附加属性。然后在XAML中,使用扩展标记将AttachPassword作为绑定的目标。
**数据流:**PasswordBox.Password->AttachedPasswordProperty<->TextBlock.TextProperty;可以发现,这里缺少了一个环节,就是PasswordBox.Password<-AttachedPasswordProperty,这个可以在AttachedPasswordProperty的回调方法中实现。这里注意增加验证机制,既代码中的isUpdating;如果不加这个验证,就会发生环形数据流(严格来说是以PasswordBox.Password为目标的逻辑上的MulitBinnd)!!会导致光标位置出现问题。
```csharp
using System.Windows;
using System.Windows.Controls;
namespace 密码绑定
{
public static class PasswordHelper
{
private static bool isUpdating = false;
public static readonly DependencyProperty AttachPasswordProperty =
DependencyProperty.RegisterAttached("AttachPassword", typeof(string), typeof(PasswordHelper), new PropertyMetadata(string.Empty, OnAttachPasswordPropertyChanged));
public static string GetAttachPassword(DependencyObject obj)
{
return (string)obj.GetValue(AttachPasswordProperty);
}
public static void SetAttachPassword(DependencyObject obj, string value)
{
obj.SetValue(AttachPasswordProperty, value);
}
public static readonly DependencyProperty AttachProperty =
DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false, OnAttachPropertyChanged));
public static bool GetAttach(DependencyObject obj)
{
return (bool)obj.GetValue(AttachProperty);
}
public static void SetAttach(DependencyObject obj, bool value)
{
obj.SetValue(AttachProperty, value);
}
private static void OnAttachPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
if (passwordBox == null)
return;
if ((bool)e.OldValue)
passwordBox.PasswordChanged -= PasswordChanged;
if ((bool)e.NewValue)
passwordBox.PasswordChanged += PasswordChanged;
}
private static void OnAttachPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (!isUpdating)
{
PasswordBox passwordBox = sender as PasswordBox;
if (passwordBox == null)
return;
passwordBox.Password = (string)e.NewValue;
}
}
private static void PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
isUpdating = true;
SetAttachPassword(passwordBox, passwordBox.Password);
isUpdating = false;
}
}
}
```
```
<PasswordBox Grid.Column="1" Margin="5"
loc:PasswordHelper.Attach="True"
loc:PasswordHelper.AttachPassword="{Binding Text, ElementName=plain, Mode=TwoWay}" >
</PasswordBox>
<TextBlock Name="plain" Grid.Row="1" Grid.Column="1" Margin="5"></TextBlock>
<Button ...></Button>
```
# 风险
PasswordBox.Password不依赖化的缘由我想是出于安全性的考虑,而View与ViewModel之间通过DataBinding进行驱动必定能发现端倪。
![snoop.png](http://upload-images.jianshu.io/upload_images/140233-fe479aa7a42370e6.png)
(看图不说话)
是否采用这种方案,主要的矛盾源头还是安全性和MVVM~