一、概述
众所周知,绑定的源既可以是依赖属性也可以是普通的CLR属性,而绑定的目标只能是依赖属性。
控件PasswordBox的Password属性不是依赖属性,不可以作为绑定的目标与后台数据进行绑定,而在MVVM模式中,前台和后台的绑定是经常需要的,为了达到这种目的,我们可以借助附加属性来实现PasswordBox的Password属性的绑定。
二、绑定思路
思路如下:
1)定义一个PasswordBoxHelper类,在类中定义PasswordProperty、AttachProperty和IsUpdatingProperty三个附加属性以及相应的属性改变事件;
2)在AttachProperty的OnAttachPropertyChanged事件中添加PasswordBox的PasswordChanged事件处理程序,这样PasswordBox控件中输入密码的时候,就会触发PasswordBoxHelper类中PasswordChanged事件处理函数;
3)PasswordChanged事件处理函数执行的时候,把控件中的信息赋值给PasswordBoxHelper类中的依赖属性PasswordProperty;
三、Demo
1 <Window x:Class="PasswordBinding.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:PasswordBinding" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="447.125" Width="525"> 9 <Grid> 10 <Grid.RowDefinitions> 11 <RowDefinition Height="134*"/> 12 <RowDefinition Height="101*"/> 13 </Grid.RowDefinitions> 14 <Grid.ColumnDefinitions> 15 <ColumnDefinition Width="60*"/> 16 <ColumnDefinition Width="457*"/> 17 </Grid.ColumnDefinitions> 18 <TextBlock Margin="10 50" Text="密码:"></TextBlock> 19 <PasswordBox Grid.Row="0" Grid.Column="1" Margin="10,50,10,157" BorderBrush="Red" local:PasswordBoxHelper.Attach ="True" Name="pwd" 20 local:PasswordBoxHelper.Password ="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 21 <TextBlock Margin="10,30,10,10" Text="显示:" Grid.Row="1" Grid.Column="0"></TextBlock> 22 <TextBlock Grid.Row="1" Grid.Column="1" Margin="10,70,10,72" Background="AliceBlue" Foreground="#FF4EB24E" Name="tbl" /> 23 <!--附加属性绑定的时候,记得一定要加括号!!!--> 24 <TextBlock Grid.Column="1" Margin="10,10,10,135" Background="AliceBlue" Foreground="#FF4EB24E" Grid.Row="1" Text="{Binding ElementName=pwd, Path=(local:PasswordBoxHelper.Password)}" /> 25 <Button Grid.Row="1" Grid.Column="1" Margin="370,135,0,0" Content="显示密码" Click="Button_Click" ></Button> 26 27 </Grid> 28 </Window>
1 using System.Windows; 2 3 namespace PasswordBinding 4 { 5 /// <summary> 6 /// Interaction logic for MainWindow.xaml 7 /// </summary> 8 public partial class MainWindow : Window 9 { 10 //private string password; 11 12 //public string Password 13 //{ 14 // get { return password; } 15 // set { password = value; } 16 //} 17 18 public string Password//依赖属性具有自动通知的能力,不需要实现INotifi接口 19 { 20 get { return (string)GetValue(PasswordProperty); } 21 set { SetValue(PasswordProperty, value); } 22 } 23 24 // Using a DependencyProperty as the backing store for Password. This enables animation, styling, binding, etc... 25 public static readonly DependencyProperty PasswordProperty = 26 DependencyProperty.Register("Password", typeof(string), typeof(MainWindow), new PropertyMetadata("")); 27 28 29 public MainWindow() 30 { 31 InitializeComponent(); 32 this.DataContext = this; 33 } 34 35 private void Button_Click(object sender, RoutedEventArgs e) 36 { 37 //tbl.Text = password; 38 tbl.Text = PasswordBoxHelper.GetPassword(pwd); 39 } 40 } 41 }
1 using System.Windows; 2 using System.Windows.Controls; 3 4 namespace PasswordBinding 5 { 6 7 public static class PasswordBoxHelper 8 { 9 10 public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordBoxHelper), 11 new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged)); 12 public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, OnAttachPropertyChanged)); 13 14 private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordBoxHelper)); 15 16 17 public static void SetAttach(DependencyObject dp, bool value) 18 { 19 dp.SetValue(AttachProperty, value); 20 } 21 22 public static bool GetAttach(DependencyObject dp) 23 { 24 return (bool)dp.GetValue(AttachProperty); 25 } 26 27 public static string GetPassword(DependencyObject dp) 28 { 29 return (string)dp.GetValue(PasswordProperty); 30 } 31 32 public static void SetPassword(DependencyObject dp, string value) 33 { 34 dp.SetValue(PasswordProperty, value); 35 } 36 37 private static bool GetIsUpdating(DependencyObject dp) 38 { 39 return (bool)dp.GetValue(IsUpdatingProperty); 40 } 41 42 private static void SetIsUpdating(DependencyObject dp, bool value) 43 { 44 dp.SetValue(IsUpdatingProperty, value); 45 } 46 47 private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 48 { 49 PasswordBox passwordBox = sender as PasswordBox; 50 passwordBox.PasswordChanged -= PasswordChanged; 51 if (!(bool)GetIsUpdating(passwordBox)) 52 { 53 passwordBox.Password = (string)e.NewValue; 54 } 55 passwordBox.PasswordChanged += PasswordChanged; 56 } 57 58 private static void OnAttachPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 59 { 60 PasswordBox passwordBox = sender as PasswordBox; 61 if (passwordBox == null) 62 { 63 return; 64 } 65 if ((bool)e.OldValue) 66 { 67 passwordBox.PasswordChanged -= PasswordChanged; 68 } 69 if ((bool)e.NewValue) 70 { 71 passwordBox.PasswordChanged += PasswordChanged; 72 } 73 } 74 75 private static void PasswordChanged(object sender, RoutedEventArgs e) 76 { 77 PasswordBox passwordBox = sender as PasswordBox; 78 SetIsUpdating(passwordBox, true); 79 SetPassword(passwordBox, passwordBox.Password); 80 SetIsUpdating(passwordBox, false); 81 } 82 } 83 }