相依性屬性中繼資料

Windows Presentation Foundation (WPF) 屬性系統包含元資料包告系統,其超越可透過反映或一般通用語言執行平臺 (CLR) 特性來報告屬性的內容。 相依性屬性的中繼資料也可由定義相依性屬性的類別唯一指派、在相依性屬性新增至不同類別時變更,以及由從定義的基底類別繼承相依性屬性的所有衍生類別明確覆寫。

必要條件

本主題假設您從 WPF 類別上現有相依性屬性取用者的觀點瞭解相依性屬性,並已閱讀 相依性屬性概觀 。 為了遵循本主題中的範例,您也應該了解 XAML 並知道如何撰寫 WPF 應用程式。

相依性屬性中繼資料的使用方式

相依性屬性中繼資料以物件的形式存在,可接受查詢來查看相依性屬性的特性。 屬性系統也經常存取此中繼資料,因為它會處理任何指定的相依性屬性。 相依性屬性的中繼資料物件可包含下列類型的資訊:

  • 相依性屬性的預設值,如果無法透過本機值、樣式、繼承等方式判斷相依性屬性的其他值,如需在指派相依性屬性值時,預設值如何參與屬性系統所使用的優先順序的完整討論,請參閱 相依性屬性值優先順序

  • 影響各擁有者類型之強制型轉或變更通知行為的回呼實作參考。 請注意,這些回呼通常是在非公用存取層級定義,因此一般無法從中繼資料取得實際參考,除非參考位於允許的存取範圍內。 如需相依性屬性回呼的詳細資訊,請參閱相依性屬性回呼和驗證

  • 如果將考慮中的相依性屬性視為 WPF 架構層級屬性,中繼資料可能會包含 WPF 架構層級相依性屬性特性,以報告服務的資訊和狀態 (例如 WPF 架構層級配置引擎和屬性繼承邏輯)。 如需相依性屬性中繼資料在這方面的詳細資訊,請參閱架構屬性中繼資料

中繼資料 API

報告屬性系統所使用之大部分中繼資料資訊的型別是 類別 PropertyMetadata 。 當相依性屬性向屬性系統註冊時,會選擇性指定中繼資料執行個體,而且若有其他類型將自身作為擁有者新增或覆寫從基底類別相依性屬性定義繼承的中繼資料,則可再次指定中繼資料執行個體 (如果屬性註冊未指定中繼資料,則會使用該類別的預設值來建立預設值 PropertyMetadata 。當您呼叫從 實例上的 DependencyObject 相依性屬性取得中繼資料的各種 GetMetadata 多載時,會傳 PropertyMetadata 回已註冊的中繼資料。

然後,類別 PropertyMetadata 衍生自 ,以提供更特定的架構分割中繼資料,例如 WPF 架構層級類別。 UIPropertyMetadata 新增動畫報告,並提供 FrameworkPropertyMetadata 上一節中所述的 WPF 架構層級屬性。 註冊相依性屬性時,可以向這些 PropertyMetadata 衍生類別註冊它們。 檢查中繼資料時,基底 PropertyMetadata 類型可能會轉換成衍生類別,以便您可以檢查更特定的屬性。

注意

中可以指定 FrameworkPropertyMetadata 的屬性特性有時會在此檔中稱為「旗標」。 當您建立新的中繼資料實例以用於相依性屬性註冊或中繼資料覆寫時,您可以使用旗標式列舉 FrameworkPropertyMetadataOptions 來指定這些值,然後將列舉的 FrameworkPropertyMetadata 可能串連值提供給建構函式。 不過,建構之後,這些選項特性會在 內 FrameworkPropertyMetadata 公開為一系列的布林屬性,而不是建構列舉值。 布林值屬性可讓您查看每個條件,而不需要將遮罩套用到旗標型列舉值以取得所需的資訊。 建構函式會使用串連 FrameworkPropertyMetadataOptions ,讓建構函式簽章的長度保持合理,而實際建構的中繼資料則會公開離散屬性,讓查詢中繼資料更直覺。

何時覆寫中繼資料及衍生類別

WPF 屬性系統已建立功能來變更相依性屬性的某些特性,而不需要完全重新實作它們。 這是由於相依性屬性位於特定類型上,因此可藉由為相依性屬性建構不同的屬性中繼資料執行個體來達成。 請注意,大多數現有相依性屬性不是虛擬屬性,因此嚴格來說,要在繼承的類別上「重新實作」這些屬性,只能藉由鏡像處理現有成員來達成。

如果您要嘗試為某個類型上的相依性屬性啟用的情節,無法藉由修改現有相依性屬性的特性來達成,則可能需要建立衍生類別,然後在該衍生類別上宣告自訂相依性屬性。 自訂相依性屬性的行為與 WPF API 所定義的相依性屬性相同。 如需自訂相依性屬性的詳細資訊,請參閱自訂相依性屬性

您無法覆寫的相依性屬性有一個值得注意的特性,那就是它的實值型別。 如果您繼承的相依性屬性所具有的行為大致符合需求,但此相依性屬性需要不同的類型,就必須實作自訂相依性屬性,而且可能需要透過類型轉換或自訂類別上的其他實作連結屬性。 此外,您無法取代現有的 ValidateValueCallback ,因為這個回呼存在於註冊欄位本身,而不是在其中繼資料內。

變更現有中繼資料的情節

如果您使用現有相依性屬性的中繼資料,變更相依性屬性中繼資料的一個常見情節是變更預設值。 變更或新增屬性系統回呼是更進階的情節。 如果您的衍生類別實作在相依性屬性之間有不同的相互關係,就可能會想要這麼做。 具有同時支援程式碼和宣告式使用方式之程式設計模型的條件之一,就是屬性必須能夠以任何順序設定。 因此,任何相依性屬性都必須在沒有內容的情況下進行 Just-In-Time 設定,不能依賴建構函式中可能找到的設定順序來進行設定。 如需屬性系統在這方面的詳細資訊,請參閱相依性屬性回呼和驗證。 請注意,驗證回呼不是中繼資料的一部分,而是相依性屬性識別項的一部分。 因此,您無法藉由覆寫中繼資料來變更驗證回呼。

在某些情況下,您可能也想變更現有相依性屬性上的 WPF 架構層級屬性中繼資料選項。 這些選項會將 WPF 架構層級屬性的某些已知條件傳達給其他 WPF 架構層級處理序 (例如配置系統)。 設定選項通常只有在註冊新的相依性屬性時才會完成,但也可以在 或 AddOwner 呼叫時變更 WPF 架構層級屬性中繼資料 OverrideMetadata 。 如需要使用的特定值和詳細資訊,請參閱架構屬性中繼資料。 如需如何針對新註冊的相依性屬性設定這些選項的詳細資訊,請參閱自訂相依性屬性

覆寫中繼資料

覆寫中繼資料的目的,主要是讓您有機會變更各種中繼資料衍生的行為,這些行為會套用到類型上的相依性屬性。 中繼資料一節會詳細說明原因。 如需詳細資訊,包括一些程式碼範例,請參閱覆寫相依性屬性的中繼資料

您可以在註冊呼叫期間為相依性屬性提供屬性中繼資料。 Register 不過,在許多情況下,當您的類別繼承該相依性屬性時,您可能會想要為類別提供特定類型的中繼資料。 您可以呼叫 OverrideMetadata 方法來執行此動作。 如需 WPF API 的範例,類別 FrameworkElement 是先註冊相依性屬性的類型 Focusable 。 但是類別 Control 會覆寫相依性屬性的中繼資料,以提供自己的初始預設值、將其從 false 變更為 true ,否則會重複使用原始 Focusable 實作。

當您覆寫中繼資料時,不同的中繼資料特性會被合併或取代。

這個行為是由 實作, Merge 而且可以在衍生的中繼資料類別上覆寫。

覆寫附加屬性中繼資料

在 WPF 中,附加屬性會實作為相依性屬性。 這表示它們也有屬性中繼資料,可供個別類別覆寫。 WPF 中附加屬性的範圍考慮通常是任何 DependencyObject 可以設定附加屬性。 因此,任何 DependencyObject 衍生類別都可以覆寫任何附加屬性的中繼資料,因為它可能會在 類別的實例上設定。 您可以覆寫預設值、回呼或 WPF 架構層級特性報告屬性。 如果在類別執行個體上設定附加屬性,則會套用這些覆寫屬性中繼資料特性。 例如,您可以覆寫預設值,只要沒有另外設定屬性,就會將覆寫值回報為類別執行個體上附加屬性的值。

注意

屬性 Inherits 與附加屬性無關。

新增類別作為現有相依性屬性的擁有者

類別可以使用 方法,將本身新增為已經註冊 AddOwner 之相依性屬性的擁有者。 這可讓類別使用原本註冊給其他類型的相依性屬性。 新增的類別通常不是原先註冊該相依性屬性作為擁有者之類型的衍生類別。 實際上,這可讓類別及其衍生類別「繼承」相依性屬性實作,而原始擁有者類別和新增的類別不需要在同一個真實類別階層中。 此外,新增的類別 (及所有衍生類別) 接著可為原始相依性屬性提供特定類型的中繼資料。

除了透過屬性系統公用程式方法自行新增作為擁有者,新增的類別也應在本身上宣告其他公用成員,讓相依性屬性完全融合在屬性系統中,並能公開給程式碼和標記。 新增現有相依性屬性的類別與定義新自訂相依性屬性的類別一樣,也必須公開該相依性屬性的物件模型。 第一個要公開的成員是相依性屬性識別項欄位。 此欄位應該是 public static readonly 類型的 DependencyProperty 欄位,指派給呼叫的 AddOwner 傳回值。 要定義的第二個成員是 Common Language Runtime (CLR) 「wrapper」 屬性。 包裝函式可讓您更方便在程式碼中操作相依性屬性(您避免每次呼叫 SetValue ,而且只能在包裝函式本身進行一次呼叫)。 包裝函式的實作方式與註冊自訂相依性屬性時實作包裝函式的方式完全相同。 如需實作相依性屬性的詳細資訊,請參閱自訂相依性屬性新增相依性屬性的擁有者類型

AddOwner 和附加屬性

您可以呼叫 AddOwner 由擁有者類別定義為附加屬性的相依性屬性。 一般這麼做的原因是要將先前的附加屬性公開為非附加相依性屬性。 接著,您會公開傳 AddOwner 回值做為欄位做為 public static readonly 相依性屬性識別碼,並定義適當的「包裝函式」屬性,讓屬性出現在成員資料表中,並支援類別中的非附加屬性使用方式。

另請參閱