附加依賴屬性

什麼時候用

附加屬性是一個依賴屬性,可以應用於任何 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 的屬性。