附加屬性概觀

附加屬性是一個 XAML 觀念。 附加屬性可在物件上設定附加屬性/值組,但這些屬性不屬於原始物件定義。 附加屬性通常定義為相依性屬性的特殊形式,在擁有者類型的物件模型中沒有傳統的屬性包裝函式。

必要條件

我們假設您已了解相依性屬性的基本概念,並已閱讀相依性屬性概觀

XAML 中的附加屬性

在 XAML 中,您可以使用 AttachedPropertyProvider.PropertyName 語法來設定附加屬性。 以下是如何在 XAML 中設定 Canvas.Left 的範例。

<Canvas>
  <Button Canvas.Left="50">Hello</Button>
</Canvas>

注意

我們只是使用 Canvas.Left 作為附加屬性的範例,而沒有完全解釋為什麼要使用它。 如果您想詳細了解 Canvas.Left 的用途,以及 Canvas 如何處理其子版面配置,請參閱 Canvas 參考主題或使用 XAML 定義版面配置

為什麼要使用附加屬性?

附加屬性是一種逃避編碼約定的方法,這些約定可能會阻止關係中的不同物件在執行階段相互傳遞訊息。 當然,您可以將屬性放在公用基本類別上,以便每個物件都可以取得和設定該屬性。 但您可能想在大量案例中執行此操作,這將使您的基本類別因可共用屬性而膨脹。 甚至可能會出現這樣的情況:數百個子系中可能只有兩個試圖使用一個屬性。 這樣的類別設計並不恰當。 為了解決這個問題,附加屬性概念使物件能夠為其自己的類別結構未定義的屬性指派值。 在物件樹狀結構中建立各種物件後,定義類別可以在執行階段從子物件讀取值。

例如,子元素可以使用附加屬性來通知其父元素如何在 UI 中呈現它們。 Canvas.Left 附加屬性就是這種情況。 Canvas.Left 建立為附加屬性,因為它是在 Canvas 元素中包含的元素上設定的,而不是在 Canvas 本身上設定的。 然後,任何可能的子元素都使用 Canvas.LeftCanvas.Top 來指定其在 Canvas 版面配置容器父系中的版面配置位移。 附加屬性讓這個屬性能夠運作,而不需要雜亂處理基底元素的物件模型,而且每個屬性都只套用到許多可能版面配置容器的其中一個。 相反,許多版面配置容器會實作它們自己的附加屬性集。

為了實作附加屬性,Canvas 類別定義了一個名為 Canvas.LeftProperty 的靜態 DependencyProperty 欄位。 然後,Canvas 提供 SetLeftGetLeft 方法作為附加屬性的公用存取子,以啟用 XAML 設定和執行階段值存取。 對於 XAML 和依賴性屬性系統,這組 API 滿足了一種模式,可為附加屬性啟用特定的 XAML 語法,並將值儲存在依賴性屬性存放區中。

所屬類型如何使用附加屬性

儘管可以在任何 XAML 元素 (或任何基礎 DependencyObject) 上設定附加屬性,但這並不代表設定該屬性一定會產生有形的結果,或者該值會被存取。 可定義附加屬性的類型通常會遵循下列其中一個情境︰

  • 定義附加屬性的類型是其他物件關係中的父物件。 子物件將為附加屬性設定值。 附加的屬性擁有者類型具有一些固有的行為,這些行為會迭代其子元素,獲取值,並在物件生命週期中的某個時刻對這些值進行動作 (版面配置動作、SizeChanged 等)
  • 可定義附加屬性的類型會用作各種可能的父元素和內容模型的子元素,但該資訊不一定是版面配置資訊。。
  • 附加屬性會向服務報告資訊,而不是向另一個 UI 元素報告資訊。

有關這些情境和擁有類型的詳細資訊,請參閱自訂附加屬性的「深入了解 Canvas.Left」一節。

程式碼中的附加屬性

附加屬性沒有像其他相依性屬性那樣易於取得和設定存取的典型屬性包裝函式。 這是因為附加屬性不一定屬於已設定屬性之執行個體的程式碼中心物件模型。 (儘管不常見,但允許定義一個屬性,該屬性既是其他類型可以在其自身上設定的附加屬性,又在所屬類型上具有常規屬性用法。)

有兩種方法可以在程式碼中設定附加屬性:使用屬性系統 API,或使用 XAML 模式存取子。 這些技術的最終結果幾乎是相同的,因此使用哪一種主要取決於編碼風格。

使用屬性系統

Windows 執行階段的附加屬性會實作為相依性屬性,以便屬性系統可以將值儲存在共用相依性屬性存放區中。 因此,附加屬性公開了所屬類別的相依性屬性識別碼。

若要在程式碼中設定附加屬性,請呼叫 SetValue 方法,並傳遞用作該附加屬性的識別碼的 DependencyProperty 欄位。 (您也可以傳遞要設定的值。)

若要取得程式碼中附加屬性的值,您可以呼叫 GetValue 方法,並再次傳遞當作識別碼的 DependencyProperty 欄位。

使用 XAML 存取子模式

當 XAML 剖析成物件樹狀結構時,XAML 處理器必須能夠設定附加的屬性值。 附加屬性的擁有者類型必須實作以 GetPropertyNameSetPropertyName 形式命名的專用存取子方法。 這些專用存取子方法也是一種取得或設定程式碼附加屬性的方法。 從程式碼觀點,附加屬性類似具有方法存取子而非屬性存取子的支援欄位,而且該支援欄位可以存在於任何物件,而不必特別進行定義。

下一個範例示範如何透過 XAML 存取子 API 在程式碼中設定附加屬性。 在此範例中,myCheckBoxCheckBox 類別的執行個體。 最後一行是實際設定值的程式碼; 之前的幾行只是建立執行個體及其父子關係。 如果您使用的是屬性系統,則未註解的最後一行是語法。 如果您使用的是 XAML 存取子模式,則註解的最後一行是語法。

    Canvas myC = new Canvas();
    CheckBox myCheckBox = new CheckBox();
    myCheckBox.Content = "Hello";
    myC.Children.Add(myCheckBox);
    myCheckBox.SetValue(Canvas.TopProperty,75);
    //Canvas.SetTop(myCheckBox, 75);
    Dim myC As Canvas = New Canvas()
    Dim myCheckBox As CheckBox= New CheckBox()
    myCheckBox.Content = "Hello"
    myC.Children.Add(myCheckBox)
    myCheckBox.SetValue(Canvas.TopProperty,75)
    ' Canvas.SetTop(myCheckBox, 75)
Canvas myC;
CheckBox myCheckBox;
myCheckBox.Content(winrt::box_value(L"Hello"));
myC.Children().Append(myCheckBox);
myCheckBox.SetValue(Canvas::TopProperty(), winrt::box_value(75));
// Canvas::SetTop(myCheckBox, 75);
    Canvas^ myC = ref new Canvas();
    CheckBox^ myCheckBox = ref new CheckBox();
    myCheckBox->Content="Hello";
    myC->Children->Append(myCheckBox);
    myCheckBox->SetValue(Canvas::TopProperty,75);
    // Canvas::SetTop(myCheckBox, 75);

自訂附加屬性

有關如何定義自訂附加屬性的程式碼範例以及有關使用附加屬性情境的更多範例,請參閱自訂附加屬性

附加屬性參考的特殊語法

附加屬性名稱中的點是識別模式的重要部分。 有時,當語法或情況將點視為具有其他含義時,就會出現歧義。 例如,將點視為繫結路徑的物件模型周遊。 在大多數涉及此類歧義的情況下,附加屬性有一種特殊的語法,可以使內部點仍然剖析為附加屬性的 owner.property 分隔符號。

  • 若要將附加屬性指定為動畫目標路徑的一部分,請將附加屬性名稱括在括號 (“()”) 中,例如 "(Canvas.Left)"。 如需詳細資訊,請參閱 Property-path 語法 (機器翻譯)。

警告

Windows 執行階段 XAML 實現的現有限制是您無法為自訂附加屬性設定動畫。

  • 若要將附加屬性指定為從資源檔案到 x:Uid 的資源參考的目標屬性,請使用注入程式碼樣式的特殊語法,完整使用:方括號 ("[]") 內的聲明,以刻意建立範圍中斷。 例如,假設存在一個 <TextBlock x:Uid="Title" /> 元素,則資源檔案中針對該執行個體上的 Canvas.Top 值的資源索引鍵為「Title.[using:Windows.UI.Xaml.Controls]Canvas.Top」。 有關資源檔案和 XAML 的詳細資訊,請參閱快速入門:翻譯 UI 資源