共用方式為


相依性屬性中繼資料

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

必要條件

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

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

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

  • 相依性屬性的預設值 (如果無法由區域數值、樣式、繼承等判斷出相依性屬性的其他值)。如需預設值在屬性系統指派相依性屬性的值時所佔優先順序的完整說明,請參閱相依性屬性值優先順序

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

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

中繼資料 API

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

接著會從中衍生 PropertyMetadata 類別,以針對 WPF 架構層級類別等架構細部提供更具體的中繼資料。 UIPropertyMetadata 新增動畫報告,FrameworkPropertyMetadata 提供上一節所述的 WPF 架構層級屬性。 註冊相依性屬性時,它們可以與這些 PropertyMetadata 衍生類別一起註冊。 當查看中繼資料時,基底 PropertyMetadata 類型有可能會轉換為衍生類別,以便您查看更具體的屬性。

注意

可在 FrameworkPropertyMetadata 中指定的屬性特性在本文中有時會稱為「旗標」。 當您建立新的中繼資料執行個體以供相依性屬性註冊或中繼資料覆寫使用時,可使用旗標型列舉 FrameworkPropertyMetadataOptions 指定這些值,然後將列舉的可能串連值提供給 FrameworkPropertyMetadata 建構函式。 不過,一旦建構好之後,這些選項特性會以一連串的布林值屬性 (而非建構列舉值) 的形式公開在 FrameworkPropertyMetadata 內。 布林值屬性可讓您查看每個條件,而不需要將遮罩套用到旗標型列舉值以取得所需的資訊。 建構函式會使用串連的 FrameworkPropertyMetadataOptions 讓建構函式簽章保持合理的長度,而實際建構的中繼資料則會公開個別屬性,使查詢中繼資料更容易進行。

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

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

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

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

變更現有中繼資料的情節

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

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

覆寫中繼資料

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

相依性屬性的屬性中繼資料可在註冊呼叫 (Register) 期間提供。 不過,在許多情況下,當您的類別繼承該相依性屬性時,您可能會想要為類別提供特定類型的中繼資料。 您可以藉由呼叫 OverrideMetadata 方法執行這項作業。 以 WPF API 的範例而言,FrameworkElement 類別是先註冊 Focusable 相依性屬性的類型。 但 Control 類別會覆寫相依性屬性的中繼資料,以提供自己的初始預設值 (也就是將它從 false 變更為 true),並重複使用原始 Focusable 實作。

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

此行為是由 Merge 實作,可在衍生的中繼資料類別上覆寫。

覆寫附加屬性中繼資料

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

注意

Inherits 屬性與附加屬性無關。

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

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

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

AddOwner 和附加屬性

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

另請參閱