感谢UniApi对本博客的的大力赞助。 创作不易,如果您觉得有帮助,请 支持LIncol29! 为了让我能够继续创作更好的内容,你也可以选择订阅博客的 VIP ,包年VIP仅需10元/年,所有VIP内容免费观看
附加属性
附加属性,在XAML中是一种特殊的依赖属性,它允许给这个对象添加一个不属于它的值(另一个对象的值),从而改变另一个对象的值。它们通常用于扩展已有控件的功能,使其能够响应特定布局容器或服务提供的属性。简单来说,附加属性就像是“借用”其他类的属性来增强自身的功能。
比如 Grid.Row Grid.Column就属于附加属性。
如何自定义附加属性
PasswordBox的 Password不是依赖属性,不支持直接绑定,需要自定义附加属性。
PasswordBox的属性绑定步骤
- 新建PasswordBoxHelper类 使用propa 快捷键,然后按下 tab键,VS会自动创建附加属性的定义模板
创建MyPwd以及IsBinding两个附加属性。 - MyPwd附加属性中,默认值为string.Empty 当值发生改变时触发回调函数OnPwdPropertyChanged
- 在OnPwdPropertyChanged 函数中将MyPwd(改变的值)传给PasswordBox的Password前端控件,并且需要设置光标位置
- IsBinding附加属性中,new PropertyMetadata(false, OnPropertyChanged),默认值为false 当为true时,触发OnPropertyChanged
- OnPropertyChanged当为新值,给PasswordBox的PasswordChanged事件绑定方法OnPwdChanged
- OnPwdChanged方法主要是调用SetPwd方法,设置Pwd附加属性值。将PasswordBox的Password前端控件 –> MyPwd
代码示例
PasswordBoxHelper类
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
namespace MVVMDemo
{
public class PasswordBoxHelper
{
//附加属性 MyPwd
public static string GetMyPwd(DependencyObject obj)
{
return (string)obj.GetValue(MyPwdProperty);
}
public static void SetMyPwd(DependencyObject obj, string value)
{
obj.SetValue(MyPwdProperty, value);
}
// Using a DependencyProperty as the backing store for MyPwd. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPwdProperty =
DependencyProperty.RegisterAttached("MyPwd", typeof(string), typeof(PasswordBoxHelper), new PropertyMetadata(string.Empty,OnPwdPropertyChanged));
//属性是否改变 Pwd -> Passwordbox
private static void OnPwdPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = d as PasswordBox;
if (passwordBox == null)
{
return;
}
passwordBox.Password = (string)e.NewValue;
SetSelection(passwordBox, passwordBox.Password.Length,0 );
}
/// <summary>
/// 设置光标位置
/// </summary>
/// <param name="passwordBox"></param>
/// <param name="start">光标开始位置</param>
/// <param name="length">选中长度</param>
private static void SetSelection(PasswordBox passwordBox, int start, int length)
{
passwordBox.GetType()
.GetMethod("Select", BindingFlags.Instance | BindingFlags.NonPublic)
.Invoke(passwordBox, new object[] { start, length
});
}
//附加属性 IsBinding
public static bool GetIsBinding(DependencyObject obj)
{
return (bool)obj.GetValue(IsBindingProperty);
}
public static void SetIsBinding(DependencyObject obj, bool value)
{
obj.SetValue(IsBindingProperty, value);
}
// Using a DependencyProperty as the backing store for IsBinding. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBindingProperty =
DependencyProperty.RegisterAttached("IsBinding", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false,OnPropertyChanged));
//passwordbox -> mypwd
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = d as PasswordBox;
if (passwordBox == null)
return;
if ((bool)e.NewValue)
{
//SetMyPwd(passwordBox, passwordBox.Password);
passwordBox.PasswordChanged += OnPwdChanged;
}
if ((bool)e.OldValue)
{
passwordBox.PasswordChanged -= OnPwdChanged;
}
}
private static void OnPwdChanged(object sender, RoutedEventArgs e)
{
PasswordBox pwd = sender as PasswordBox;
SetMyPwd(pwd, pwd.Password);
}
}
}
前端控件绑定
<PasswordBox x:Name="pwdbox" Grid.Row="1" Grid.Column="1" FontSize="25" VerticalAlignment="Center" Width="200" HorizontalAlignment="Left"
local:PasswordBoxHelper.IsBinding="True"
local:PasswordBoxHelper.MyPwd="{Binding Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
/>
<StackPanel Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" Grid.ColumnSpan="2">
<TextBlock Grid.Row="1" Grid.Column="0" Text="密码: " FontSize="25" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<TextBox Text="{Binding ElementName=pwdbox,Path=(local:PasswordBoxHelper.MyPwd)}" FontSize="25" Width="200" HorizontalAlignment="Right"/>
</StackPanel>
//双向绑定附加属性
local:PasswordBoxHelper.IsBinding="True"
local:PasswordBoxHelper.MyPwd="{Binding Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
//绑定源元素为:pwdbox的值,Path指用来绑定的属性路径,(...)表示附加属性
//XAML 引擎看到 Path=(local:PasswordBoxHelper.MyPwd),就去找名为 pwdbox 的元素,读取它身上的 PasswordBoxHelper.GetMyPwd(pwdbox);– 把这个值赋给当前控件的 Text。
Text="{Binding ElementName=pwdbox,Path=(local:PasswordBoxHelper.MyPwd)}"
推荐文章
如果你对MVVM已经有个掌握,可以查看进阶文章:如何使用ReactiveUI框架快速实现MVVM模式。