自定义WPF的PasswordBox控件,解决MVVM绑定问题

    最近在用MVVM框架做一个用户登录模块,涉及到密码框绑定的问题遇到阻碍。WPF中有现成的密码输入框控件PasswordBox,通过Password属性获取密码,但是Password属性不能进行数据绑定,原因是Password属性不是依赖属性。

    网上常见的解决思路是“将密码框的密码和某一个缓冲区进行同步, 缓冲区在和后台进行绑定. 其中密码框与缓冲区之间的同步可采用事件进行通知, 并将缓冲区打造成依赖属性, 然后缓冲区就支持绑定了, 并给后台提供正确的密码”,这个方法确实可以达到绑定的功能,但是有一个问题“在更改了密码框的密码后, 需要手动更新密码框插入符(CaretIndex)的位置”,虽然也有相对应的解决方案,但效果不好。本思路的解决方案请参考周银辉的[WPF]实现密码框的密码绑定》http://www.cnblogs.com/zhouyinhui/archive/2009/08/27/1554943.html

    另外一种思路是重写PasswordBox,在此参考,该作者已经用TextBox作为基础重写了类似PasswordBox的控件

Passwords in WPF: How to find yours and how to prevent it being found

http://www.codeproject.com/Articles/30976/Passwords-in-WPF-How-to-find-yours-and-how-to-prev

为了实现数据绑定,笔者将该控件作了相应修改,实现如下所示:

    /// <summary>
    /// More secure PasswordBox based on TextBox control
    /// </summary>
    public class SecurePasswordBox : TextBox
    {
        // Fake char to display in Visual Tree
        private char PWD_CHAR = '';

        /// <summary>
        /// Only copy of real password
        /// </summary>
        /// <remarks>For more security use System.Security.SecureString type instead</remarks>
        private string _password = string.Empty;

        /// <summary>
        /// TextChanged event handler for secure storing of password into Visual Tree,
        /// text is replaced with PWD_CHAR chars, clean text is keept into
        /// Text property (CLR property not snoopable without mod)   
        /// </summary>
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            if (dirtyBaseText == true)
                return;

            string currentText = this.BaseText;

            int selStart = this.SelectionStart;
            if (currentText.Length < _password.Length)
            {
                // Remove deleted chars          
                _password = _password.Remove(selStart, _password.Length - currentText.Length);
                SetRealText(this, _password);
            }
            if (!string.IsNullOrEmpty(currentText))
            {
                for (int i = 0; i < currentText.Length; i++)
                {
                    if (currentText[i] != PWD_CHAR)
                    {
                        // Replace or insert char
                        if (this.BaseText.Length == _password.Length)
                        {
                            _password = _password.Remove(i, 1).Insert(i, currentText[i].ToString());
} else { _password = _password.Insert(i, currentText[i].ToString());
} } }
   SetRealText(this, _password);
this.BaseText = new string(PWD_CHAR, _password.Length); this.SelectionStart = selStart; } base.OnTextChanged(e); } // flag used to bypass OnTextChanged private bool dirtyBaseText; /// <summary> /// Provide access to base.Text without call OnTextChanged /// </summary> private string BaseText { get { return base.Text; } set { dirtyBaseText = true; base.Text = value; dirtyBaseText = false; } } /// <summary> /// Clean Password /// </summary> public new string Text { get { return _password; } set { _password = value; this.BaseText = new string(PWD_CHAR, value.Length); } } //数据绑定用的附加属性RealText public static string GetRealText(DependencyObject obj) { return (string)obj.GetValue(RealTextProperty); } public static void SetRealText(DependencyObject obj, string value) { obj.SetValue(RealTextProperty, value); } // Using a DependencyProperty as the backing store for RealText. This enables animation, styling, binding, etc... public static readonly DependencyProperty RealTextProperty = DependencyProperty.RegisterAttached("RealText", typeof(string), typeof(SecurePasswordBox), new UIPropertyMetadata("")); }

数据绑定如下:【注意:附加属性的绑定默认是单向的】

<local:SecurePasswordBox  local:SecurePasswordBox.RealText="{Binding Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Text="{Binding Password,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"/>


 

 

 

转载于:https://www.cnblogs.com/jojinshallar/articles/3167507.html

MVVM模式下,PassWordBox的密码不能直接绑定到ViewModel的属性,因为密码是敏感信息,不应该以明文形式存储在内存中。因此,我们需要使用PasswordBox的SecureString属性来存储密码,并在ViewModel中创建一个SecureString类型的属性来接收密码。 首先,在XAML中,我们需要将PassWordBoxPasswordChanged事件与Command绑定,以便在密码发生变化时触发Command执行。例如: ``` <PasswordBox PasswordChanged="{Binding PasswordChangedCommand}" /> ``` 然后,在ViewModel中,我们需要创建一个SecureString类型的属性来接收密码,并创建一个Command来处理密码变化事件,例如: ``` public class LoginViewModel : INotifyPropertyChanged { private SecureString _securePassword; public SecureString SecurePassword { get { return _securePassword; } set { _securePassword = value; OnPropertyChanged(nameof(SecurePassword)); } } public ICommand PasswordChangedCommand => new RelayCommand<PasswordBox>((pb) => { SecurePassword = pb.SecurePassword; }); // INotifyPropertyChanged implementation... } ``` 在这个示例中,我们创建了一个SecurePassword属性来接收密码,并使用PasswordBox的SecurePassword属性将密码赋值给SecurePassword。我们还创建了一个PasswordChangedCommand来处理密码变化事件,该Command使用RelayCommand实现,并将PasswordBox作为参数传递。当密码发生变化时,Command会将SecurePassword属性设置为新密码。 需要注意的是,由于SecureString无法直接转换为字符串,因此我们需要在处理密码时使用相应的方法来转换或处理SecureString。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值