【WPF学习笔记】WPF 中使用附加属性解决 PasswordBox 的数据绑定问题

WPF 中使用附加属性解决 PasswordBox 的数据绑定问题

  • 1、前言
  • 2、实现步骤
  • 3、完整代码
    • 3.1、页面代码
    • 3.2、数据绑定辅助类 LoginPasswordBoxHelper
    • 3.3、其它代码
  • 4、附加功能:输入框添加水印
  • 5、效果展示

1、前言

在 WPF 开发中 View 中的数据展示我们常通过 Binding 进行绑定。但是,使用 Binding 有一个前提:绑定的目标只能是依赖属性。 而 PasswordBox 控件中的 Password 并不是一个依赖属性,所以我们在使用 Password 时无法直接进行数据绑定。为了解决这个问题,我们就需要自己定义依赖属性。标题中的 “附加属性” 是依赖属性的一种特殊形式。

2、实现步骤

注:附加属性的定义方式:在 Visual Studio 中输入 propa ,然后按下两次 Tab 键即可。

2.1、定义一个 LoginPasswordBoxHelper 类,并在页面 xaml 代码中添加命名空间,该类用于辅助解决数据绑定问题。

xmlns:vm="clr-namespace:PasswordBoxDemo.ViewModel"

2.2、在类中添加用于绑定的 Password 属性

public static class LoginPasswordBoxHelper
{
    public static string GetPassword(DependencyObject obj)
    {
        return (string)obj.GetValue(PasswordProperty);
    }

    public static void SetPassword(DependencyObject obj, string value)
    {
        obj.SetValue(PasswordProperty, value);
    }

    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.RegisterAttached("Password", typeof(string), typeof(LoginPasswordBoxHelper), new PropertyMetadata(""));
    
}

这个时候就可以在页面的 xaml 中的 PasswordBox 中添加如下数据绑定了:


但是,这时候只是提供了一个属性给 PasswordBox 用于 Binding,输入内容后数据没有任何更改效果。

因为当在 PasswordBox 中填写密码时,没有启动对应的事件将密码 Changed 到后端 ViewModel 中的 Password 属性

这时就需要再建一个附加属性 IsPasswordBindingEnable,用于给 PasswordBox 的更改添加事件,并在事件中更改到 后端 ViewModel 中的 Password 属性。

2.3、添加附加属性 IsPasswordBindingEnable,用于给 PasswordBox 的添加更改事件

当 IsPasswordBindingEnable=“True” 时,给 PasswordBox 的 PasswordChanged 事件添加处理程序PasswordBoxPasswordChanged;

PasswordBoxPasswordChanged 作用:当页面中 PasswordBox 输入的值发生改变时,通过 SetPassword 完成数据更改,从而实现完整的数据绑定功能。


public static bool GetIsPasswordBindingEnable(DependencyObject obj)
{
    return (bool)obj.GetValue(IsPasswordBindingEnableProperty);
}

public static void SetIsPasswordBindingEnable(DependencyObject obj, bool value)
{
    obj.SetValue(IsPasswordBindingEnableProperty, value);
}

public static readonly DependencyProperty IsPasswordBindingEnableProperty =
    DependencyProperty.RegisterAttached("IsPasswordBindingEnable", typeof(bool), typeof(LoginPasswordBoxHelper),
                                        new FrameworkPropertyMetadata(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;
        }
    }
}

static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
{
    var passwordBox = (PasswordBox)sender;
    if (!String.Equals(GetPassword(passwordBox), passwordBox.Password))
    {
        SetPassword(passwordBox, passwordBox.Password);
    }
}

3、完整代码

3.1、页面代码

Login.xaml


    
        
            
            
            
        
        
        
        

Login.xaml.cs

using PasswordBoxDemo.ViewModel;
using System.Windows;

namespace PasswordBoxDemo
{
    public partial class Login : Window
    {
        private MainViewModel resource;
        public Login()
        {
            InitializeComponent();
            resource = new MainViewModel();
            this.DataContext = resource;
        }

    }
}

3.2、数据绑定辅助类 LoginPasswordBoxHelper

using System;
using System.Windows;
using System.Windows.Controls;

namespace PasswordBoxDemo.ViewModel
{
    public static class LoginPasswordBoxHelper
    {
        public static string GetPassword(DependencyObject obj)
        {
            return (string)obj.GetValue(PasswordProperty);
        }

        public static void SetPassword(DependencyObject obj, string value)
        {
            obj.SetValue(PasswordProperty, value);
        }
        
        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.RegisterAttached("Password", typeof(string), typeof(LoginPasswordBoxHelper), new PropertyMetadata(""));

        public static bool GetIsPasswordBindingEnable(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsPasswordBindingEnableProperty);
        }

        public static void SetIsPasswordBindingEnable(DependencyObject obj, bool value)
        {
            obj.SetValue(IsPasswordBindingEnableProperty, value);
        }
        
        public static readonly DependencyProperty IsPasswordBindingEnableProperty =
            DependencyProperty.RegisterAttached("IsPasswordBindingEnable", typeof(bool), typeof(LoginPasswordBoxHelper),
                new FrameworkPropertyMetadata(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;
                }
            }
        }

        static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
        {
            var passwordBox = (PasswordBox)sender;
            if (!String.Equals(GetPassword(passwordBox), passwordBox.Password))
            {
                SetPassword(passwordBox, passwordBox.Password);
            }
        }
    }
}

3.3、其它代码

ViewModel:

using GalaSoft.MvvmLight;

namespace PasswordBoxDemo.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
        }

        private string userName;

        public string UserName
        {
            get { return userName; }
            set { userName = value; RaisePropertyChanged(); }
        }

        private string password;

        public string Password
        {
            get { return password; }
            set { password = value; RaisePropertyChanged(); }
        }

    }
}

4、附加功能:输入框添加水印

实现水印添加也可以用类似上述的方法实现,具体步骤如下:

4.1、在 LoginPasswordBoxHelper 类中添加附加属性 ShowWaterMark,用与切换水印展示状态;

public static bool GetShowWaterMark(DependencyObject obj)
{
    return (bool)obj.GetValue(ShowWaterMarkProperty);
}

public static void SetShowWaterMark(DependencyObject obj, bool value)
{
    obj.SetValue(ShowWaterMarkProperty, value);
}

/// 
/// 控制水印显示
/// 
public static readonly DependencyProperty ShowWaterMarkProperty =
    DependencyProperty.RegisterAttached("ShowWaterMark", typeof(bool), typeof(LoginPasswordBoxHelper),
                                        new FrameworkPropertyMetadata(true, OnShowWaterMarkChanged));

private static void OnShowWaterMarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}

4.2、自定义水印展示样式


    
    

5、效果展示

【WPF学习笔记】WPF 中使用附加属性解决 PasswordBox 的数据绑定问题_第1张图片

你可能感兴趣的:(wpf)