标准依赖属性

什么时候用

实际上,所有 WPF 控件都会大量使用依赖项属性。依赖项属性允许使用许多仅使用标准 CLR 属性不可能的 WPF 功能,包括但不限于支持样式,动画,数据绑定,值继承和更改通知。

TextBox.Text 属性是需要标准依赖项属性的简单示例。如果 Text 是标准 CLR 属性,则无法进行数据绑定。

<TextBox Text="{Binding FirstName}" />

如何定义

依赖属性只能在从 DependencyObject 派生的类中定义,例如 FrameworkElementControl 等。

在不必记住语法的情况下创建标准依赖项属性的最快方法之一是通过键入 propdp 然后按下来使用 propdp 代码段 Tab。将插入一个代码片段,然后可以对其进行修改以满足你的需求:

public class MyControl : Control
{
    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.
    // This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
            new PropertyMetadata(0));
}

你应该 Tab 通过代码段的不同部分进行必要的更改,包括更新属性名称,属性类型,包含类类型和默认值。

重要的惯例

这里有一些重要的约定/规则:

  1. **为依赖项属性创建 CLR 属性。**此属性用于对象的代码隐藏或其他使用者。它应该调用 GetValueSetValue,以便消费者不必这样做。

  2. 正确命名依赖项属性。 DependencyProperty 字段应该是 public static readonly。它应该具有与 CLR 属性名称对应的名称,并以 Property 结尾,例如 TextTextProperty

  3. **不要向 CLR 属性的 setter 添加其他逻辑。**依赖项属性系统(特别是 XAML)不使用 CLR 属性。如果要在属性值更改时执行操作,则必须通过 PropertyMetadata 提供回调:

    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl),
            new PropertyMetadata(0, MyPropertyChangedHandler));
    
    private static void MyPropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        // Use args.OldValue and args.NewValue here as needed.
        // sender is the object whose property changed.
        // Some unboxing required.
    }
    

绑定模式

为了消除在绑定中指定 Mode=TwoWay 的需要(类似于 TextBox.Text 的行为),更新代码以使用 FrameworkPropertyMetadata 而不是 PropertyMetadata 并指定适当的标志:

public static readonly DependencyProperty MyPropertyProperty =
    DependencyProperty.Register("MyProperty", typeof(int), typeof(MyControl), 
        new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));