附加依赖属性

什么时候用

附加属性是一个依赖属性,可以应用于任何 DependencyObject,以增强了解属性存在的各种控件或服务的行为。

附加属性的一些用例包括:

  1. 让父元素迭代其子元素并以某种方式对子元素进行操作。例如,Grid 控件使用 Grid.RowGrid.ColumnGrid.RowSpanGrid.ColumnSpan 附加属性将元素排列成行和列。
  2. 使用自定义模板向现有控件添加视觉效果,例如在应用范围内为空文本框添加水印,而无需子类 TextBox
  3. 为部分或全部现有控件提供通用服务或功能,例如 ToolTipServiceFocusManager。这些通常被称为附加行为
  4. 当需要继承可视树时,例如类似于 DataContext 的行为。

这进一步说明了 Grid 用例中发生的事情:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <Label Grid.Column="0" Content="Your Name:" />
    <TextBox Grid.Column="1" Text="{Binding FirstName}" />
</Grid>

Grid.Column 不是 LabelTextBox 上存在的属性。而是,Grid 控件查看其子元素并根据附加属性的值排列它们。

如何定义

我们将继续使用 Grid 作为这个例子。Grid.Column 的定义如下所示,但为了简洁,排除了 DependencyPropertyChangedEventHandler

public static readonly DependencyProperty RowProperty =
    DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid),
        new FrameworkPropertyMetadata(0, ...));

public static void SetRow(UIElement element, int value)
{
    if (element == null)
        throw new ArgumentNullException("element");

    element.SetValue(RowProperty, value);
}

public static int GetRow(UIElement element)
{
    if (element == null)
        throw new ArgumentNullException("element");

    return ((int)element.GetValue(RowProperty));
}

由于附加属性可以附加到各种各样的项目,因此它们不能实现为 CLR 属性。而是引入了一对静态方法。

因此,与标准依赖项属性相比,附加属性也可以在不是从 DependencyObject 派生的类中定义。

适用于常规依赖项属性的相同命名约定也适用于此:依赖项属性 RowProperty 具有相应的方法 GetRowSetRow

注意事项

MSDN 上所述

虽然属性值继承似乎适用于非附加依赖项属性,但未定义运行时树中某些元素边界的非附加属性的继承行为。始终使用 RegisterAttached 来注册在元数据中指定 Inherits 的属性。