一、概述
众所周知,绑定的源既可以是依赖属性也可以是普通的CLR属性,而绑定的目标只能是依赖属性。
控件PasswordBox的Password属性不是依赖属性,不可以作为绑定的目标与后台数据进行绑定,而在MVVM模式中,前台和后台的绑定是经常需要的,为了达到这种目的,我们可以借助附加属性来实现PasswordBox的Password属性的绑定。
二、绑定思路
思路如下:
1)定义一个PasswordBoxHelper类,在类中定义PasswordProperty、AttachProperty和IsUpdatingProperty三个附加属性以及相应的属性改变事件;
2)在AttachProperty的OnAttachPropertyChanged事件中添加PasswordBox的PasswordChanged事件处理程序,这样PasswordBox控件中输入密码的时候,就会触发PasswordBoxHelper类中PasswordChanged事件处理函数;
3)PasswordChanged事件处理函数执行的时候,把控件中的信息赋值给PasswordBoxHelper类中的依赖属性PasswordProperty;
三、Demo
<Window x:Class="PasswordBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PasswordBinding"
mc:Ignorable="d"
Title="MainWindow" Height="447.125" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="134*"/>
<RowDefinition Height="101*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*"/>
<ColumnDefinition Width="457*"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="10 50" Text="密码:"></TextBlock>
<PasswordBox Grid.Row="0" Grid.Column="1" Margin="10,50,10,157" BorderBrush="Red" local:PasswordBoxHelper.Attach ="True" Name="pwd"
local:PasswordBoxHelper.Password ="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Margin="10,30,10,10" Text="显示:" Grid.Row="1" Grid.Column="0"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="10,70,10,72" Background="AliceBlue" Foreground="#FF4EB24E" Name="tbl" />
<!--附加属性绑定的时候,记得一定要加括号!!!-->
<TextBlock Grid.Column="1" Margin="10,10,10,135" Background="AliceBlue" Foreground="#FF4EB24E" Grid.Row="1" Text="{Binding ElementName=pwd, Path=(local:PasswordBoxHelper.Password)}" />
<Button Grid.Row="1" Grid.Column="1" Margin="370,135,0,0" Content="显示密码" Click="Button_Click" ></Button>
</Grid>
</Window>
using System.Windows;
namespace PasswordBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//private string password;
//public string Password
//{
// get { return password; }
// set { password = value; }
//}
public string Password//依赖属性具有自动通知的能力,不需要实现INotifi接口
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
// Using a DependencyProperty as the backing store for Password. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(string), typeof(MainWindow), new PropertyMetadata(""));
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//tbl.Text = password;
tbl.Text = PasswordBoxHelper.GetPassword(pwd);
}
}
}
using System.Windows;
using System.Windows.Controls;
namespace PasswordBinding
{
public static class PasswordBoxHelper
{
public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordBoxHelper),
new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));
public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, OnAttachPropertyChanged));
private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordBoxHelper));
public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}
public static bool GetAttach(DependencyObject dp)
{
return (bool)dp.GetValue(AttachProperty);
}
public static string GetPassword(DependencyObject dp)
{
return (string)dp.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject dp, string value)
{
dp.SetValue(PasswordProperty, value);
}
private static bool GetIsUpdating(DependencyObject dp)
{
return (bool)dp.GetValue(IsUpdatingProperty);
}
private static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}
private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
passwordBox.PasswordChanged -= PasswordChanged;
if (!(bool)GetIsUpdating(passwordBox))
{
passwordBox.Password = (string)e.NewValue;
}
passwordBox.PasswordChanged += PasswordChanged;
}
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 PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
SetIsUpdating(passwordBox, true);
SetPassword(passwordBox, passwordBox.Password);
SetIsUpdating(passwordBox, false);
}
}
}
