WPF 的 XAML 和自訂類別

在 Common Language Runtime (CLR) 架構中實作的 XAML 支援在任何 Common Language Runtime (CLR) 語言中定義自訂類別或結構的能力,然後使用 XAML 標記存取該類別。 您可以混合使用 Windows Presentation Foundation (WPF)定義的類型和相同標記檔案內的自訂類型,通常是將自訂類型對應至 XAML 命名空間前置詞。 本主題討論自訂類別必須滿足才能用作 XAML 項目的需求。

應用程式或組件中的自訂類別

在 XAML 中使用的自訂類別可以透過兩種不同的方式定義:在程式碼後置或其他產生主要 Windows Presentation Foundation (WPF) 應用程式的程式碼內,或做為個別元件中的類別,例如做為類別庫使用的可執行檔或 DLL。 所有這些方法都會有特定優缺點。

  • 建立類別庫的優點是可以跨許多不同的可能應用程式來共用任何這類自訂類別。 不同的程式庫也方便控制應用程式的版本控制問題,並簡化如何建立所要類別用法作為 XAML 頁面上根項目的類別。

  • 在應用程式中定義自訂類別的優點在於這項技巧相當簡單,並將在引進主要應用程式可執行檔以外的個別組件時所遇到的部署和測試問題降到最少。

  • 不論定義於相同或不同組件中,都需要在 CLR 命名空間與 XML 命名空間之間對應自訂類別,才能當成項目用於 XAML 中。 請參閱 WPF XAML 的 XAML 命名空間和命名空間對應

作為 XAML 項目之自訂類別的需求

若要可具現化為物件項目,您的類別必須符合下列需求︰

  • 自訂類別必須是公用,並支援預設 (無參數) 公用建構函式 (如需結構相關附註,請參閱下節)。

  • 自訂類別不能是巢狀類別。 巢狀類別及其一般 CLR 使用語法中的「點」會干擾其他 WPF 和/或 XAML 功能,例如附加屬性。

除了啟用物件項目語法之外,您的物件定義也會啟用採用該物件作為值類型之任何其他公用屬性的屬性項目語法。 這是因為物件現在可以具現化為物件項目,並且可以填入這類屬性的屬性項目值。

結構

您定義為自訂類型的結構一律可以在 WPF 中的 XAML 中建構。這是因為 CLR 編譯器會隱含地為將所有屬性值初始化為其預設值的結構建立無參數建構函式。 在某些情況下,您可能不想要結構的預設建構行為和 (或) 物件項目用法。 這可能是因為結構是要填入值並在概念上當成聯集運作;其中,所包含的值可能會有互斥解譯,因此無法設定其屬性。 這類結構的 WPF 範例為 GridLength 。 一般而言,這類結構應該實作類型轉換子;如此,使用可建立結構值的不同解譯或模式的字串慣例,即可透過屬性形式表示這些值。 結構也應該透過非無參數建構函式公開程式碼建構的類似行為。

作為 XAML 屬性之自訂類別的屬性需求

屬性必須參考實值型別(例如基本類型),或是針對具有無參數建構函式的類型,或是 XAML 處理器可以存取的專用型別轉換子使用類別。 在 CLR XAML 實作中,XAML 處理器可以透過原生支援語言基本類型,或透過 將 的 型別或成員套用 TypeConverterAttribute 至支援類型定義中的這類轉換器

或者,屬性可以參考抽象類別類型或介面。 針對抽象類別或介面,XAML 剖析預期屬性值必須填入可實作介面的實體類別執行個體,或衍生自抽象類別之類型的執行個體。

屬性可以宣告於抽象類別上,但只可以設定於衍生自抽象類別的實值類別上。 這是因為建立 類別的物件專案完全需要 類別的公用無參數建構函式。

TypeConverter 啟用屬性語法

如果您在類別層級提供專用屬性化類型轉換子,則套用的類型轉換可啟用任何需要具現化該類型之屬性 (property) 的屬性 (attribute) 語法。 類型轉換器不會啟用型別的物件專案使用方式;只有該類型的無參數建構函式的存在可啟用物件專案使用方式。 因此,除非類型本身也支援物件項目語法,否則已啟用類型轉換子的屬性一般無法用於屬性語法。 這個的例外狀況是您可以指定屬性項目語法,但讓屬性項目包含字串。 該使用方式基本上相當於屬性語法使用方式,而且這類用法並不常見,除非需要更健全的屬性值空白字元處理。 例如,以下是取用字串的屬性 (property) 項目用法以及對等的屬性 (attribute) 用法︰

<Button>Hallo!
  <Button.Language>
    de-DE
  </Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>

允許屬性語法的屬性範例,但不允許透過 XAML 包含物件元素的屬性專案語法,是採用 Cursor 類型的各種屬性。 類別 Cursor 具有專用的型別轉換子 CursorConverter ,但不會公開無參數建構函式,因此 Cursor 即使實際 Cursor 類型是參考型別,屬性仍只能透過屬性語法來設定。

每個屬性的類型轉換子

或者,屬性本身可以宣告屬性層級的類型轉換子。 這可啟用「迷你語言」,藉由根據適當類型處理屬性的傳入字串值做為作業的輸入 ConvertFrom ,來具現化屬性類型的物件。 這項作業一般是要提供方便使用的存取子,而不是在 XAML 中設定屬性的唯一方法。 不過,您也可以針對您想要使用未提供無參數建構函式或屬性型別轉換器的現有 CLR 型別,使用型別轉換器的類型轉換器。 WPF API 的範例是採用 型別 CultureInfo 的特定屬性。 在此情況下,WPF 會使用現有的 Microsoft .NET Framework CultureInfo 類型,以更好地解決舊版架構中使用的相容性和移轉案例,但 CultureInfo 類型不支援必要的建構函式或類型層級類型轉換,以便直接作為 XAML 屬性值使用。

只要公開具有 XAML 用法的屬性,特別的是,如果您是控制項作者,則應該強烈考慮支援該屬性與相依性屬性。 如果您使用 XAML 處理器的現有 Windows Presentation Foundation (WPF) 實作,因為您可以使用備份來改善效能 DependencyProperty ,這特別正確。 相依性屬性會公開使用者預期 XAML 可存取屬性之屬性的屬性系統功能。 這包括動畫、資料繫結和樣式支援這類功能。 如需詳細資訊,請參閱自訂相依性屬性XAML 載入和相依性屬性

撰寫並屬性化類型轉換子

您偶爾需要撰寫自訂 TypeConverter 衍生類別,以提供屬性類型的類型轉換。 如需如何衍生自 並建立可支援 XAML 使用方式的類型轉換器,以及如何套用 的 TypeConverterAttribute 指示,請參閱 TypeConverters 和 XAML

自訂類別事件上 XAML 事件處理常式屬性語法的需求

若要當做 CLR 事件使用,事件必須公開為支援無參數建構函式之類別上的公用事件,或是可在衍生類別上存取事件的抽象類別。 為了方便作為路由事件使用,您的 CLR 事件應該實作明確的 addremove 方法,以新增和移除 CLR 事件簽章的處理常式,並將這些處理常式轉送至 AddHandlerRemoveHandler 方法。 這些方法會在附加事件的執行個體上新增或移除路由事件處理常式存放區的處理常式。

注意

您可以使用 直接註冊路由事件的 AddHandler 處理常式,並刻意不定義公開路由事件的 CLR 事件。 通常不會建議您使用此方式,因為事件不會啟用用於附加處理常式的 XAML 屬性語法,而且產生的類別將針對該類型的功能提供較不容易明瞭的 XAML 檢視。

撰寫集合屬性

採用集合類型的屬性具有 XAML 語法,可讓您指定新增至集合的物件。 此語法有兩個值得注意的功能。

  • 本身為集合物件的物件不需要指定於物件項目語法中。 只要在 XAML 中指定採用集合類型的屬性,該集合類型的存在就是隱含的。

  • 標記中集合屬性的子項目會處理成集合的成員。 一般而言,是透過 Add 這類清單/字典方法,或透過索引子,執行對集合成員的程式碼存取。 但是 XAML 語法不支援方法或索引子 (例外狀況︰XAML 2009 可以支援方法,但使用 XAML 2009 限制可能的 WPF 用法;請參閱 XAML 2009 語言功能)。 集合很明顯是建置項目樹狀結構的很常見需求,而且您需要某個方法在宣告式 XAML 中填入這些集合。 因此,會處理集合屬性的子項目,方法是將它們新增至為集合屬性類型值的集合。

.NET Framework XAML 服務實作,因此 WPF XAML 處理器會使用下列構成集合屬性的定義。 屬性的屬性類型必須實作下列其中一項:

CLR 中的所有這些類型都會有 Add 方法,而 XAML 處理器使用此方法,在建立物件圖形時,將項目新增至基礎集合。

注意

WPF XAML 處理器不支援集合偵測泛型 ListDictionary 介面和 IList<T>IDictionary<TKey,TValue> 介面 。 不過,您可以使用 類別 List<T> 做為基類,因為它會直接實作 IListDictionary<TKey,TValue> 做為基類,因為它會直接實作 IDictionary

當您宣告採用集合的屬性時,請注意如何在類型的新執行個體中初始化該屬性值。 如果您未將屬性實作為相依性屬性,則讓屬性使用可呼叫集合類型建構函式的支援欄位就已足夠。 如果您的屬性是相依性屬性,則可能需要將集合屬性初始化為預設類型建構函式的一部分。 這是因為相依性屬性會從中繼資料取得其預設值,而且您通常不想要集合屬性的初始值成為靜態共用集合。 一個包含類型執行個體應該要有一個集合執行個體。 如需詳細資訊,請參閱自訂相依性屬性

您可以實作集合屬性的自訂集合類型。 由於隱含集合屬性處理,自訂集合類型不需要提供無參數建構函式,才能在 XAML 中隱含使用。 不過,您可以選擇為集合類型提供無參數建構函式。 這是相當實用的做法。 除非您提供無參數建構函式,否則您無法明確地將集合宣告為物件專案。 部分標記作者可能會想要將明確集合視為標記樣式。 此外,當您建立使用集合類型做為屬性值的新物件時,無參數建構函式可以簡化初始化需求。

宣告 XAML 內容屬性

XAML 語言會定義 XAML 內容屬性的概念。 每個可用於物件語法中的類別都只能有一個 XAML 內容屬性。 若要宣告屬性為類別的 XAML 內容屬性,請套用 ContentPropertyAttribute 做為類別定義的一部分。 將預期 XAML 內容屬性的名稱指定為 Name 屬性中的 。 屬性會依名稱指定為字串,而不是如 的 PropertyInfo 反映建構。

您可以將集合屬性指定為 XAML 內容屬性。 這會導致使用該屬性,藉此,物件項目可以有一或多個子項目,而不需要任何中介集合物件項目或屬性項目標記。 這些項目則是視為 XAML 內容屬性的值,並新增至支援集合執行個體。

一些現有的 XAML 內容屬性使用 Object 屬性類型。 這可讓 XAML 內容屬性接受基本值,例如 String ,以及取得單一參考物件值。 如果您遵循此模型,則您的類型會負責類型判斷,以及可能類型的處理。 內容類型的一般原因是 Object 支援將物件內容新增為字串的簡單方法(其會接收預設的簡報處理),或新增指定非預設簡報或其他資料的物件內容進階方法。

序列化 XAML

在特定情況下,例如,如果您是控制項作者,則可能也要確保可在 XAML 中具現化的任何物件表示也都可以序列化回對等的 XAML 標記。 本主題未描述序列化需求。 請參閱控制項撰寫概觀項目樹狀結構和序列化

另請參閱