在MVVM中使用PasswordBox控件

在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~





郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。