定義搭配 .NET XAML 服務使用的自訂類型Define custom types for use with .NET XAML Services

當您定義屬於商務物件的自訂類型,或是沒有相依于特定架構的類型時,可以遵循 XAML 的一些最佳作法。When you define custom types that are business objects or are types that do not have a dependency on specific frameworks, there are certain best practices for XAML you can follow. 如果您遵循這些做法,.NET XAML 服務及其 XAML 讀取器和 XAML 寫入器可以探索您類型的 XAML 特性,並使用 XAML 型別系統在 XAML 節點資料流程中提供適當的標記法。If you follow these practices, .NET XAML Services and its XAML readers and XAML writers can discover the XAML characteristics of your type and give it appropriate representation in a XAML node stream using the XAML type system. 本主題說明型別定義、成員定義以及型別或成員的 CLR 類型的最佳作法。This topic describes best practices for type definitions, member definitions, and CLR attributing of types or members.

XAML 的函式模式和類型定義Constructor Patterns and Type Definitions for XAML

若要在 XAML 中具現化為物件元素,自訂類別必須符合下列需求:To be instantiated as an object element in XAML, a custom class must meet the following requirements:

  • 自訂類別必須是公用的,而且必須公開無參數公用的函式。The custom class must be public and must expose a parameterless public constructor. (如需結構相關附註,請參閱下節)。(See following section for notes regarding structures.)

  • 自訂類別不得為嵌套類別。The custom class must not be a nested class. 在完整名稱路徑中的額外「點」讓類別命名空間的除法不明確,並干擾其他 XAML 功能,例如附加屬性。The extra "dot" in the full-name path makes the class-namespace division ambiguous, and interferes with other XAML features such as attached properties. 如果物件可以具現化為物件專案,則建立的物件可以填滿將物件做為其基礎型別的任何屬性(property element)形式的屬性(property element)。If an object can be instantiated as an object element, the created object can fill the property element form of any properties that take the object as their underlying type.

如果您啟用值轉換器,您仍然可以針對不符合這些準則的類型提供物件值。You can still provide object values for types that do not meet these criteria, if you enable a value converter. 如需詳細資訊,請參閱 XAML 的類型轉換器和標記延伸For more information, see Type Converters and Markup Extensions for XAML.

結構Structures

結構一律可以透過 CLR 定義在 XAML 中進行。Structures are always able to be constructed in XAML, by CLR definition. 這是因為 CLR 編譯器會隱含地為結構建立無參數的函式。This is because a CLR compiler implicitly creates a parameterless constructor for a structure. 這個函式會將所有屬性值初始化為其預設值。This constructor initializes all property values to their defaults.

在某些情況下,不需要結構的預設結構行為。In some cases, the default construction behavior for a structure is not desirable. 這可能是因為結構的目的是要將值填滿,並且在概念上以聯集的方式運作。This might be because the structure is intended to fill values and function conceptually as a union. 以聯集的形式,包含的值可能會有互斥的解讀,因此不會設定其任何屬性。As a union, the contained values might have mutually exclusive interpretations, and therefore, none of its properties are settable. WPF 詞彙中的這類結構範例為 GridLengthAn example of such a structure in the WPF vocabulary is GridLength. 這類結構應該採用型別轉換子,藉由使用可建立結構值之不同解讀或模式的字串慣例,以屬性形式表示值。Such structures should implement a type converter so that the values can be expressed in attribute form, by using string conventions that create the different interpretations or modes of the structure values. 此結構也應該透過非參數的函式來公開程式碼結構的類似行為。The structure should also expose similar behavior for code construction through a non-parameterless constructor.

介面Interfaces

介面可以用來做為成員的基礎類型。Interfaces can be used as underlying types of members. XAML 類型系統會檢查可指派的清單,並預期以值形式提供的物件可以指派給介面。The XAML type system checks the assignable list and expects that the object that is provided as the value can be assigned to the interface. 如果有相關的可指派型別支援 XAML 結構需求,就不需要將介面呈現為 XAML 型別。There is no concept of how the interface must be presented as a XAML type as long as a relevant assignable type supports the XAML construction requirements.

Factory 方法Factory Methods

Factory 方法是 XAML 2009 功能。Factory methods are a XAML 2009 feature. 它們會修改物件必須具有無參數的函式的 XAML 原則。They modify the XAML principle that objects must have parameterless constructors. 本文中未記載 Factory 方法。Factory methods are not documented in this article. 請參閱 x:FactoryMethod指示詞。See x:FactoryMethod Directive.

列舉Enumerations

列舉具有 XAML 原生類型轉換行為。Enumerations have XAML native type conversion behavior. XAML 中指定的列舉常數名稱是根據基礎列舉型別來解析,並且將列舉值傳回給 XAML 物件寫入器。Enumeration constant names specified in XAML are resolved against the underlying enumeration type, and return the enumeration value to a XAML object writer.

XAML 針對已套用的列舉支援旗標樣式用法 FlagsAttributeXAML supports a flags-style usage for enumerations with FlagsAttribute applied. 如需詳細資訊,請參閱 XAML 語法的詳細資訊。For more information, see XAML Syntax In Detail. (Xaml 語法的詳細 資訊是針對 WPF 物件撰寫的,但該主題中大部分的資訊都與特定執行架構無關的 xaml 有關。 ) (XAML Syntax In Detail is written for the WPF audience, but most of the information in that topic is relevant for XAML that is not specific to a particular implementing framework.)

成員定義Member Definitions

類型可以定義 XAML 用法的成員。Types can define members for XAML usage. 類型可以定義可供 XAML 使用的成員,即使該特定型別不是 XAML 可用也是一樣。It's possible for types to define members that are XAML-usable even if that specific type is not XAML-usable. 這是可能的,因為 CLR 繼承。This is possible because of CLR inheritance. 只要有一些繼承成員的型別支援 XAML 使用方式做為型別,而成員支援其基礎類型的 XAML 使用方式,或有原生 XAML 語法可用,該成員就可以使用 XAML。So long as some type that inherits the member supports XAML usage as a type, and the member supports XAML usage for its underlying type or has a native XAML syntax available, that member is XAML-usable.

屬性Properties

如果您使用一般 CLR 和存取子模式和語言適當的 keywording,將屬性定義為公用 CLR 屬性, get set XAML 型別系統可以將屬性報告為具有提供給屬性之適當資訊的成員 XamlMember ,例如 IsReadPublicIsWritePublicIf you define properties as a public CLR property using the typical CLR get and set accessor patterns and language-appropriate keywording, the XAML type system can report the property as a member with appropriate information provided for XamlMember properties, such as IsReadPublic and IsWritePublic.

特定屬性可以藉由套用來啟用文字語法 TypeConverterAttributeSpecific properties can enable a text syntax by applying TypeConverterAttribute. 如需詳細資訊,請參閱 XAML 的類型轉換器和標記延伸For more information, see Type Converters and Markup Extensions for XAML.

如果沒有文字語法或原生 XAML 轉換,而且沒有進一步的間接取值(例如標記延伸使用方式),則在 XAML 型別系統中 (的屬性型別, TargetType) 必須能夠將目標型別視為 CLR 型別,以將實例傳回 xaml 物件寫入器。In the absence of a text syntax or native XAML conversion and in the absence of further indirection, such as a markup extension usage, the type of a property (TargetType in the XAML type system) must be able to return an instance to a XAML object writer by treating the target type as a CLR type.

如果使用 XAML 2009,如果不符合先前的考慮, X:Reference 標記延伸 可以用來提供值;不過,這比型別定義問題更是使用問題。If using XAML 2009, x:Reference Markup Extension can be used to provide values if the previous considerations are not met; however, that is more of a usage issue than a type definition issue.

事件Events

如果您將事件定義為公用 CLR 事件,XAML 型別系統可以將附隨報告為具有 as 的 IsEvent 成員 trueIf you define events as a public CLR event, the XAML type system can report the event as a member with IsEvent as true. 連接事件處理常式不在 .NET XAML 服務功能的範圍內;線路會留給特定的架構和實施。Wiring the event handlers is not within the scope of .NET XAML Services capabilities; wiring is left to specific frameworks and implementations.

方法Methods

方法的內嵌程式碼不是預設的 XAML 功能。Inline code for methods is not a default XAML capability. 在大多數情況下,您不會直接從 XAML 參考方法成員,而 XAML 中方法的角色只是提供對特定 XAML 模式的支援。In most cases, you do not directly reference method members from XAML, and the role of methods in XAML is only to provide support for specific XAML patterns. x:FactoryMethod 指示詞是例外狀況。x:FactoryMethod Directive is an exception.

欄位Fields

CLR 設計方針不鼓勵非靜態欄位。CLR design guidelines discourage nonstatic fields. 針對靜態欄位,您只能透過 X:Static 標記延伸來存取靜態域值;在此情況下,您不會在 CLR 定義中執行任何特殊作業來公開 x:Static 使用的欄位。For static fields, you can access static field values only through x:Static Markup Extension; in this case you are not doing anything special in the CLR definition to expose a field for x:Static usages.

可附加成員Attachable Members

可附加的成員會透過定義型別的存取子方法模式,對 XAML 公開。Attachable members are exposed to XAML through an accessor method pattern on a defining type. 定義型別本身不需要當做物件使用 XAML。The defining type itself does not need to be XAML-usable as an object. 事實上,常見的模式是宣告服務類別,其角色是擁有可附加的成員並執行相關的行為,但不提供任何其他功能(例如 UI 標記法)。In fact, a common pattern is to declare a service class whose role is to own the attachable member and implement the related behaviors, but serve no other function such as a UI representation. 在下列各節中,預留位置 屬性 名稱代表可附加成員的名稱。For the following sections, the placeholder PropertyName represents the name of your attachable member. 該名稱在 XamlName 文法中必須是有效的。That name must be valid in the XamlName Grammar.

請注意這些模式與類型的其他方法之間的名稱衝突。Be cautious of name collisions between these patterns and other methods of a type. 如果有符合其中一個模式的成員存在,則它可以被 XAML 處理器視為可附加的成員使用路徑,即使這不是您的目的。If a member exists that matches one of the patterns, it can be interpreted as an attachable member usage pathway by a XAML processor even if that was not your intention.

GetPropertyName 存取子The GetPropertyName Accessor

存取子的簽章 GetPropertyName 必須是:The signature for the GetPropertyName accessor must be:

public static object GetPropertyName(object target)

  • target 物件可以指定為實作中的更特定類型。The target object can be specified as a more specific type in your implementation. 您可以使用此值來限定可附加成員的使用方式;預期範圍之外的使用方式將會擲回不正確轉換例外狀況,然後由 XAML 剖析錯誤呈現。You can use this to scope the usage of your attachable member; usages outside your intended scope will throw invalid cast exceptions that are then surfaced by a XAML parse error. 參數名稱不是必要的 target ,但 target 在大部分的執行中依慣例命名。The parameter name target is not a requirement, but is named target by convention in most implementations.

  • 傳回值可以指定為實作中的更特定類型。The return value can be specified as a more specific type in your implementation.

若要 TypeConverter 針對可附加成員的屬性用法支援啟用的文字語法,請套用 TypeConverterAttribute 至存取子 GetPropertyNameTo support a TypeConverter enabled text syntax for attribute usage of the attachable member, apply TypeConverterAttribute to the GetPropertyName accessor. 套用至 get 而不是 set 直覺化; 不過,這個慣例可支援可序列化之唯讀可附加成員的概念,在設計工具案例中很有用。Applying to the get instead of the set may seem non-intuitive; however, this convention can support the concept of read-only attachable members that are serializable, which is useful in designer scenarios.

SetPropertyName 存取子The SetPropertyName Accessor

存取子的簽章 SetPropertyName 必須是:The signature for the SetPropertyName accessor must be:

public static void SetPropertyName(object target, object value)

  • target您可以將物件指定為您的實作為中的更特定類型,具有與上一節所述相同的邏輯和結果。The target object can be specified as a more specific type in your implementation, with same logic and consequences as described in the previous section.

  • value 物件可以指定為實作中的更特定類型。The value object can be specified as a more specific type in your implementation.

請記住,這個方法的值是來自 XAML 使用方式的輸入,通常是在屬性表單中。Remember that the value for this method is the input coming from the XAML usage, typically in attribute form. 在屬性表單中,必須有 text 語法的值轉換器支援,而且您可以在 s 存取子上進行屬性 GetPropertyNameFrom attribute form there must be value converter support for a text syntax, and you attribute on the GetPropertyNames accessor.

可附加的成員存放區Attachable Member Stores

存取子方法通常不足以提供方法,將可附加的成員值放入物件圖形中,或從物件圖形取出值並正確地加以序列化。The accessor methods are typically not enough to provide a means to place attachable member values into an object graph, or to retrieve values out of the object graph and serialize them properly. 若要提供這項功能,先前存取子簽章 target 中的物件必須能夠儲存值。To provide this functionality, the target objects in the previous accessor signatures must be capable of storing values. 儲存機制應該與可附加的成員主體一致,該成員可附加至可附加成員不在成員清單中的目標。The storage mechanism should be consistent with the attachable member principle that the member is attachable to targets where the attachable member is not in the members list. .NET XAML 服務透過 Api 和提供可附加的成員存放區的實作為方法 IAttachedPropertyStore AttachablePropertyServices.NET XAML Services provides an implementation technique for attachable member stores through the APIs IAttachedPropertyStore and AttachablePropertyServices. IAttachedPropertyStore XAML 寫入器會使用來探索存放區的執行,而且應該在存取子的類型上執行 targetIAttachedPropertyStore is used by the XAML writers to discover the store implementation, and should be implemented on the type that is the target of the accessors. 靜態 AttachablePropertyServices api 用於存取子的主體內,並由其參考可附加的成員 AttachableMemberIdentifierThe static AttachablePropertyServices APIs are used within the body of the accessors, and refer to the attachable member by its AttachableMemberIdentifier.

正確地將型別、成員和元件的特性化,是為了將 XAML 類型系統資訊回報給 .NET XAML 服務的重要。Correctly attributing your types, members, and assemblies is important in order to report XAML type system information to .NET XAML Services. 如果適用下列其中一種情況,則報告 XAML 類型系統資訊是相關的:Reporting XAML type system information is relevant if either of the following situations apply:

  • 您想要搭配直接以 .NET XAML 服務 XAML 讀取器和 XAML 寫入器為基礎的 XAML 系統使用類型。You intend your types for use with XAML systems that are directly based on .NET XAML Services XAML readers and XAML writers.
  • 您可以根據 xaml 讀取器和 XAML 寫入器,定義或使用以 XAML 為基礎的架構。You define or use a XAML-utilizing framework that's based on those XAML readers and XAML writers.

如需與自訂類型的 XAML 支援相關之每個 XAML 相關屬性的清單,請參閱 自訂類型和程式庫的 Xaml 相關 CLR 屬性For a listing of each XAML-related attribute that's relevant for XAML support of your custom types, see XAML-Related CLR Attributes for Custom Types and Libraries.

使用方式Usage

使用自訂類型時,標記作者必須針對包含自訂類型的元件和 CLR 命名空間對應前置詞。Usage of custom types requires that the markup author must map a prefix for the assembly and CLR namespace that contain the custom type. 本主題未記載此程式。This procedure is not documented in this topic.

存取層級Access Level

XAML 提供載入和具現化具有存取層級之類型的方法 internalXAML provides a means to load and instantiate types that have an internal access level. 提供這項功能的目的是讓使用者程式碼可以定義自己的型別,然後從同時也屬於相同使用者程式碼範圍的標記將這些類別具現化。This capability is provided so that user code can define its own types, and then instantiate those classes from markup that is also part of the same user code scope.

WPF 中的一個範例,就是當使用者程式碼定義了,其 UserControl 目的是要做為重構 UI 行為的方式,但不是任何可能的擴充機制的一部分,因為宣告支援的類別具有 public 存取層級。An example from WPF is whenever user code defines a UserControl that is intended as a way to refactor a UI behavior, but not as part of any possible extension mechanism that might be implied by declaring the supporting class with public access level. UserControl internal 如果支援的程式碼編譯成相同的元件,而這些程式碼會被視為 XAML 型別,則可以使用存取權來宣告這類。Such a UserControl can be declared with internal access if the backing code is compiled into the same assembly from which it is referenced as a XAML type.

對於在完全信任和使用下載入 XAML 的應用程式 XamlObjectWriterinternal 一律會啟用以存取層級載入類別的功能。For an application that loads XAML under full trust and uses XamlObjectWriter, loading classes with internal access level is always enabled.

針對在部分信任下載入 XAML 的應用程式,您可以使用 API 來控制存取層級的特性 XamlAccessLevelFor an application that loads XAML under partial trust, you can control the access level characteristics by using the XamlAccessLevel API. 此外,延遲機制 (例如 WPF 範本系統) 必須能夠傳播任何存取層級許可權,並保留這些許可權以進行最終的執行時間評估;這會藉由傳遞資訊在內部處理 XamlAccessLevelAlso, deferral mechanisms (such as the WPF template system) must be able to propagate any access level permissions and preserve them for the eventual run time evaluations; this is handled internally by passing the XamlAccessLevel information.

WPF 執行WPF Implementation

WPF XAML 使用部分信任存取模型,其中如果 BAML 是在部分信任下載入,則會限制為 AssemblyAccessTo baml 來源元件的存取權。WPF XAML uses a partial-trust access model where if BAML is loaded under partial trust, access is restricted to AssemblyAccessTo for the assembly that is the BAML source. 針對延遲,WPF 會使用 IXamlObjectWriterFactory.GetParentSettings 做為傳遞存取層級資訊的機制。For deferral, WPF uses IXamlObjectWriterFactory.GetParentSettings as a mechanism for passing the access level information.

在 WPF XAML 術語中, 內部型 別是由相同元件所定義的型別,也包括參考的 XAML。In WPF XAML terminology, an internal type is a type that is defined by the same assembly that also includes the referencing XAML. 這類型別可透過 XAML 命名空間進行對應,該命名空間會刻意省略對應的元件 = 部分,例如 xmlns:local="clr-namespace:WPFApplication1"Such a type can be mapped through a XAML namespace that deliberately omits the assembly= portion of a mapping, for example, xmlns:local="clr-namespace:WPFApplication1". 如果 BAML 參考內部型別,而該型別具有 internal 存取層級, GeneratedInternalTypeHelper 則會產生元件的類別。If BAML references an internal type and that type has internal access level, this generates a GeneratedInternalTypeHelper class for the assembly. 如果您想要避免 GeneratedInternalTypeHelper ,您必須使用 public 存取層級,或必須將相關的類別納入不同的元件,並使該元件相依。If you want to avoid GeneratedInternalTypeHelper, you either must use public access level, or must factor the relevant class into a separate assembly and make that assembly dependent.

另請參閱See also