附加屬性概觀

附加屬性是透過 XAML 所定義的概觀。 附加屬性是用來做為可在任何相依性物件上設定的全域屬性類型。 在 Windows Presentation Foundation (WPF) 中,附加屬性通常定義為沒有傳統屬性「包裝函式」的特殊相依性屬性形式。

先決條件

本文假設您從 Windows Presentation Foundation (WPF) 類別現有相依性屬性取用者的觀點瞭解相依性屬性,並已閱讀 相依性屬性概觀 。 若要遵循本文中的範例,您也應該瞭解 XAML 並知道如何撰寫 WPF 應用程式。

為何使用附加屬性

附加屬性的其中一個用途是允許不同的子專案指定父元素中定義之屬性的唯一值。 此案例的特定應用程式是讓子項目通知父元素如何在使用者介面 (UI) 中呈現它們。 其中一個範例是 DockPanel.Dock 屬性。 屬性 DockPanel.Dock 會建立為附加屬性,因為它的設計目的是在 內含 DockPanel 的專案上設定,而不是 DockPanel 本身。 類別 DockPanel 會定義名為 DockProperty 的靜態 DependencyProperty 欄位,然後提供 GetDockSetDock 方法做為附加屬性的公用存取子。

XAML 中的附加屬性

在 XAML 中,您可以使用 AttachedPropertyProvider.<屬性名稱> 語法來設定附加屬性。

以下是如何在 XAML 中設定 DockPanel.Dock 的範例:

<DockPanel>
    <TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

使用方式與靜態屬性有點類似;您一律參考擁有並註冊附加屬性的類型 DockPanel ,而不是參考名稱所指定的任何實例。

此外,因為 XAML 中的附加屬性是您在標記中設定的屬性,所以只有設定作業才會有任何相關性。 雖然有一些間接機制可比較值 (例如樣式中的觸發程序),但是您無法在 XAML 中直接取得屬性 (如需詳細資訊,請參閱設定樣式和範本)。

WPF 中的附加屬性實作

在 Windows Presentation Foundation (WPF)中,WPF 類型上大部分與 UI 相關的附加屬性都會實作為相依性屬性。 附加屬性是 XAML 概念,而相依性屬性則是 WPF 概念。 因為 WPF 附加屬性是相依性屬性,所以它們支援相依性屬性概念,例如屬性中繼資料,以及來自該屬性中繼資料的預設值。

擁有類型如何使用附加屬性

雖然可在任何物件上設定附加屬性,但是這不自動表示設定屬性就會產生明確結果,或者另一個物件將使用值。 一般而言,會使用附加屬性,讓來自各種可能類別階層或邏輯關聯性的物件都可以報告可定義附加屬性之類型的通用資訊。 可定義附加屬性的類型通常會遵循下列其中一個模型︰

  • 設計可定義附加屬性的類型,因此它可以是設定附加屬性值之項目的父項目。 類型接著會透過內部邏輯針對某個物件樹狀結構逐一查看其子物件,並取得值,然後以某種方式處理這些值。

  • 可定義附加屬性的類型將會用作各種可能父項目和內容模組的子項目。

  • 可定義附加屬性的類型代表服務。 其他類型設定附加屬性的值。 然後,在服務內容中評估可設定屬性的項目時,會透過服務類別的內部邏輯取得附加屬性值。

父代已定義的附加屬性範例

WPF 定義附加屬性的最典型案例是父元素支援子專案集合時,也會實作行為,其中每個子專案會個別報告行為的特定資料。

DockPanel 定義 DockPanel.Dock 附加屬性,並 DockPanel 具有類別層級程式碼做為其轉譯邏輯的一部分(特別是 MeasureOverrideArrangeOverride )。 DockPanel實例一律會檢查,以查看其任何立即子專案是否已設定 的值 DockPanel.Dock 。 如果是這樣,這些值會變成套用至該特定子項目之轉譯邏輯的輸入。 巢狀 DockPanel 實例會各自處理自己的直接子專案集合,但該行為是處理 DockPanel.Dock 值的特定 DockPanel 實作。 理論上,可能會有附加屬性影響直屬父代以外的項目。 DockPanel.Dock如果附加屬性是在沒有 DockPanel 父元素可對其採取動作的元素上設定,則不會引發錯誤或例外狀況。 這只表示已設定全域屬性值,但是沒有可以取用資訊的目前 DockPanel 父代。

程式碼中的附加屬性

WPF 中的附加屬性沒有一般 CLR「包裝函式」方法,以便輕鬆取得/設定存取。 這是因為附加屬性不一定是設定屬性之實例的 CLR 命名空間的一部分。 不過,XAML 處理器必須可以在剖析 XAML 時設定這些值。 若要支援有效的附加屬性使用方式,附加屬性的擁有者類型必須以 Get PropertyName Set PropertyName 形式 實作專用存取子方法。 這些專用存取子方法也適用於取得或設定程式碼中的附加屬性。 從程式碼觀點,附加屬性類似具有方法存取子而非屬性存取子的支援欄位,而且該支援欄位可以存在於任何物件,而不需要特別進行定義。

下列範例示範如何在程式碼中設定附加屬性。 在此範例中, myCheckBox 是 類別的 CheckBox 實例。

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
Dim myDockPanel As New DockPanel()
Dim myCheckBox As New CheckBox()
myCheckBox.Content = "Hello"
myDockPanel.Children.Add(myCheckBox)
DockPanel.SetDock(myCheckBox, Dock.Top)

與 XAML 案例類似,如果 myCheckBox 尚未新增為第四行程式碼的 myDockPanel 子項目,則第五行程式碼不會引發例外狀況,但屬性值不會與 DockPanel 父系互動,因此不會執行任何動作。 DockPanel.Dock只有與父元素存在 DockPanel 結合之子專案上設定的值,才會在轉譯的應用程式中造成有效的行為。 (在此情況下,您可以設定附加屬性,然後附加至樹狀結構。或者,您可以附加至樹狀結構,然後設定附加屬性。任一動作順序都提供相同的結果。

附加屬性中繼資料

註冊屬性時, FrameworkPropertyMetadata 會設定為指定屬性的特性,例如屬性是否會影響轉譯、測量等等。 附加屬性的中繼資料一般與相依性屬性並無不同。 如果您在附加屬性中繼資料的覆寫中指定預設值,該值會變成覆寫類別執行個體上的隱含附加屬性預設值。 具體而言,如果某個處理序透過該屬性的 Get 方法存取子來查詢附加屬性值,並指定已指定中繼資料之類別的執行個體,則會報告預設值,否則不會設定該附加屬性的值。

如果您想要啟用屬性的屬性值繼承,則應該使用附加屬性,而不是使用非附加相依性屬性。 如需詳細資訊,請參閱屬性值繼承

自訂附加屬性

建立附加屬性的時機

非定義類別的類別需要有可用的屬性設定機制時,您可以建立附加屬性。 最常見的案例是配置。 現有版面配置屬性的範例包括 DockPanel.DockPanel.ZIndexCanvas.Top 。 在這裡啟用的情節是本身為配置控制項目之子項目的項目可以個別表達其配置父項目的配置需求,且各會設定父代定義為附加屬性的屬性值。

另一個使用附加屬性的情節是類別代表一項服務,而且想要類別能夠更緊密地整合服務。

另一個案例是接收 Visual Studio WPF 設計工具的支援,例如 [屬性 ] 視窗編輯。 如需詳細資訊,請參閱控制項撰寫概觀

如前所述,如果您想要使用屬性值繼承,則應該註冊為附加屬性。

如何建立附加屬性

如果您的類別嚴格定義附加屬性以用於其他類型,則類別不必衍生自 DependencyObject 。 但是,如果您遵循附加屬性也是相依性屬性的整體 WPF 模型,則確實需要衍生自 DependencyObject

藉由宣告 public static readonly 類型的 DependencyProperty 欄位,將您的附加屬性定義為相依性屬性。 您可以使用 方法的 RegisterAttached 傳回值來定義此欄位。 功能變數名稱必須符合附加屬性名稱,並附加字串 Property ,才能遵循已建立的 WPF 模式來命名識別欄位與其所代表的屬性。 附加屬性提供者也必須提供靜態 Get PropertyName Set PropertyName 方法做為附加屬性的存取子;若無法這麼做,屬性系統就無法使用附加 屬性。

注意

如果您省略附加屬性的 get 存取子,屬性上的資料系結將無法在設計工具中運作,例如 Visual Studio 和 Blend for Visual Studio。

Get 存取子

Get PropertyName 存取子的 簽章必須是:

public static object GetPropertyName(object target)

  • target 物件可以指定為實作中的更特定類型。 例如,方法會將 DockPanel.GetDock 參數輸入為 UIElement ,因為附加屬性只打算在 實例上 UIElement 設定。

  • 傳回值可以指定為實作中的更特定類型。 例如,方法會將 GetDock 它輸入為 Dock ,因為值只能設定為該列舉。

Set 存取子

Set PropertyName 存取子的 簽章必須是:

public static void SetPropertyName(object target, object value)

  • target 物件可以指定為實作中的更特定類型。 例如,方法會將 SetDock 它輸入為 UIElement ,因為附加屬性只打算在 實例上 UIElement 設定。

  • value 物件可以指定為實作中的更特定類型。 例如,方法會將 SetDock 它輸入為 Dock ,因為值只能設定為該列舉。 請記住,當這個方法在標記的附加屬性使用方式中遇到附加屬性時,其值是來自 XAML 載入器的輸入。 該輸入是指定為標記中 XAML 屬性值的值。 因此,您使用的類型必須要有類型轉換、值序列化程式或標記延伸支援,因此,可以從屬性值 (這最後就是一個字串) 建立適當的類型。

下列範例顯示相依性屬性註冊(使用 RegisterAttached 方法),以及 Get PropertyName Set PropertyName 存取子。 在此範例中,附加屬性名稱為 IsBubbleSource。 因此,存取子必須命名為 GetIsBubbleSourceSetIsBubbleSource

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
Public Shared ReadOnly IsBubbleSourceProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsBubbleSource", GetType(Boolean), GetType(AquariumObject), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender))
Public Shared Sub SetIsBubbleSource(ByVal element As UIElement, ByVal value As Boolean)
    element.SetValue(IsBubbleSourceProperty, value)
End Sub
Public Shared Function GetIsBubbleSource(ByVal element As UIElement) As Boolean
    Return CType(element.GetValue(IsBubbleSourceProperty), Boolean)
End Function

附加屬性 (property) 的屬性 (attribute)

WPF 定義數個 .NET 屬性,這些屬性旨在提供附加屬性的相關資訊給反映進程,以及反映和屬性資訊的一般使用者,例如設計工具。 因為附加屬性的類型為無限制範圍,所以設計人員需要方法來避免使用 XAML 的特定技術實作中所定義之所有附加屬性的全域清單,讓使用者無所適從。 WPF 為附加屬性定義的 .NET 屬性可用來界定應該在屬性視窗中顯示指定附加屬性的情況。 您也可以考慮針對您自己的自訂附加屬性套用這些屬性。 .NET 屬性的用途和語法會在適當的參考頁面上描述:

深入瞭解附加屬性

  • 如需建立附加屬性的詳細資訊,請參閱註冊附加屬性

  • 如需相依性屬性和附加屬性的更進階使用方式情節,請參閱自訂相依性屬性

  • 您也可以將屬性註冊為附加屬性和相依性屬性,但仍公開「包裝函式」實作。 在此情況下,可以在該項目上設定屬性,或透過 XAML 附加屬性語法的任何項目上設定屬性。 具有適用于標準和附加用法之適當案例的屬性範例為 FrameworkElement.FlowDirection

另請參閱