.NET XAML サービスで使用するカスタム型を定義する

ビジネス オブジェクトであるカスタム型または特定のフレームワークに依存しない型のカスタム型を定義するときは、XAML に関する特定のベスト プラクティスに従って行うことができます。 これらの方法に従うと、.NET XAML サービスとその XAML リーダーおよび XAML ライターで、型が備える XAML の特徴を検出し、XAML 型システムを使用して XAML ノード ストリームでの適切な表現を与えることができます。 このトピックでは、型の定義、メンバーの定義、型またはメンバーの CLR 属性に関するベスト プラクティスについて説明します。

XAML でのコンストラクターのパターンと型の定義

XAML でのオブジェクト要素としてインスタンス化するには、クラスが次の要件を満たしている必要があります。

  • カスタム クラスはパブリックである必要があり、パラメーターなしのパブリック コンストラクターを公開する必要があります。 (構造に関する注意事項については、次のセクションを参照してください)。

  • カスタム クラスは入れ子にされたクラスであってはなりません。 完全な名前のパスの余分な "ドット" があると、クラスの名前空間の区切りがあいまいになり、添付プロパティなどの他の XAML 機能と干渉します。 オブジェクトをオブジェクト要素としてインスタンス化できる場合は、作成されたオブジェクトを使用して、基になる型としてオブジェクトを受け取るプロパティのプロパティ要素フォームを設定することができます。

その場合でも、値コンバーターを有効にすると、これらの条件を満たさない型にオブジェクト値を提供できます。 詳細については、「XAML の型コンバーターおよびマークアップ拡張機能」を参照してください。

構造体

構造体は、常に、CLR の定義を使用して XAML で作成できます。 これは、CLR コンパイラにより、構造体に対するパラメーターなしのコンストラクターが暗黙的に作成されるためです。 このコンストラクターにより、すべてのプロパティ値が既定値に初期化されます。

場合によっては、構造体の既定の構築動作が望ましくないことがあります。 これは、構造体の目的が値を設定することで、概念的に共用体として機能することが原因である可能性があります。 共用体の場合、含まれる値が相互に排他的な解釈を持つため、どのプロパティも設定できなくなることがあります。 WPF のボキャブラリにおけるそのような構造体の例としては、GridLength があります。 そのような構造体では、構造体の値の異なる解釈やモードを作成する文字列規則を使用して、値を属性形式で表現できるように、型コンバーターを実装する必要があります。 また、構造体では、パラメーターありのコンストラクターを使用してコードを構築するための同様の動作も公開する必要があります。

インターフェイス

メンバーの基になる型として、インターフェイスを使用できます。 XAML 型システムにより、割り当て可能なリストがチェックされ、値として指定されたオブジェクトをインターフェイスに割り当てることができることが想定されます。 関連する割り当て可能な型で XAML の構築要件がサポートされている限り、インターフェイスを XAML を型として提示する方法に要求される概念はありません。

ファクトリ メソッド

ファクトリ メソッドは XAML 2009 の機能です。 それらにより、オブジェクトにはパラメーターなしのコンストラクターが必要であるという XAML の原則が変更されます。 ファクトリ メソッドについては、この記事では説明しません。 「x:FactoryMethod ディレクティブ」を参照してください。

列挙

列挙型には、XAML のネイティブな型変換動作があります。 XAML で指定された列挙定数名は、基になる列挙型に解決されて、列挙値が XAML オブジェクト ライターに返されます。

XAML では、FlagsAttribute が適用された列挙型のフラグ形式の使用がサポートされています。 詳細については、「XAML 構文の詳細」を参照してください。 (「XAML 構文の詳細」は WPF のユーザーを対象に書かれていますが、そのトピックのほとんどの情報は、特定の実装フレームワークに固有ではない XAML に関連しています。)

メンバーの定義

XAML で使用するためのメンバーを型で定義できます。 XAML で使用できない型であっても、その特定の型を使用して XAML で使用できるメンバーを定義できます。 このようなことができるのは、CLR の継承のためです。 メンバーから継承された型を XAML で型として使用することができ、メンバーの基になる型を XAML で使用できる場合、またはメンバーでネイティブな XAML 構文を使用できる場合は、そのメンバーを XAML で使用できます。

プロパティ

CLR の一般的な get および set アクセサー パターンと言語に適したキーワードを使用して、プロパティをパブリック CLR プロパティとして定義すると、XAML 型システムでそのプロパティを、XamlMember のプロパティ (IsReadPublicIsWritePublic など) に提供された適切な情報を含むメンバーとして報告できます。

TypeConverterAttribute を適用することによって、特定のプロパティでテキスト構文を有効にすることができます。 詳細については、「XAML の型コンバーターおよびマークアップ拡張機能」を参照してください。

マークアップ拡張の使用など、テキスト構文またはネイティブな XAML 変換がなく、追加の間接参照がない場合は、プロパティの型 (XAML 型システムの TargetType) で、対象の型を CLR 型として扱うことにより、インスタンスを XAML オブジェクト ライターに返すことができる必要があります。

XAML 2009 を使用していて、前の考慮事項が満たされていない場合は、x:Reference マークアップ拡張を使用して値を指定できます。ただし、これは、型の定義の問題というより、使用の問題になります。

[イベント]

イベントをパブリック CLR イベントとして定義すると、XAML 型システムでそのイベントを IsEventtrue のメンバーとして報告できます。 イベント ハンドラーの接続は、.NET XAML サービスの機能の範囲内ではありません。接続は、特定のフレームワークと実装に委ねられます。

メソッド

メソッドのインライン コードは、XAML の既定の機能ではありません。 ほとんどの場合、XAML からメソッドのメンバーを直接参照することはなく、XAML でのメソッドの役割は、特定の XAML パターンのサポートを提供することだけです。 x:FactoryMethod ディレクティブは例外です。

フィールド

CLR のデザイン ガイドラインでは、非静的フィールドは推奨されません。 静的フィールドの場合は、x:Static マークアップ拡張を使用することによってのみ、静的フィールドの値にアクセスできます。この場合、x:Static で使用できるようにフィールドを公開するため、CLR の定義で特別なことは行いません。

アタッチ可能なメンバー

アタッチ可能なメンバーは、定義している型のアクセサー メソッド パターンを通じて XAML に公開されます。 定義している型自体は、オブジェクトとして XAML で使用できる必要はありません。 実際、一般的なパターンは、アタッチ可能なメンバーを所有して関連する動作を実装することが役割であるサービス クラスを宣言することですが、UI 表現などの他の機能は提供しません。 以下のセクションで、プレースホルダー PropertyName はアタッチ可能なメンバーの名前を表しています。 その名前は、XamlName の文法で有効である必要があります。

これらのパターンと、型の他のメソッドとの間での、名前の競合に注意してください。 いずれかのパターンに一致するメンバーが存在する場合、それが意図したことではない場合でも、そのメンバーが XAML プロセッサによってアタッチ可能なメンバーの使用経路として解釈される可能性があります。

GetPropertyName アクセサー

GetPropertyName アクセサーのシグネチャは次の形式にする必要があります。

public static object GetPropertyName(object target)

  • target オブジェクトは、実装のより具体的な型として指定することができます。 これを使用して、アタッチ可能なメンバーの使用のスコープを指定することができます。意図したスコープの外部で使用すると、無効なキャスト例外がスローされ、XAML 解析エラーによって表示されます。 パラメーター名 target は要件ではありませんが、ほとんどの実装では規約によって target という名前が付けられます。

  • 戻り値は、実装のより具体的な型として指定することができます。

アタッチ可能なメンバーを属性として使用するために TypeConverter が有効なテキスト構文をサポートするには、TypeConverterAttributeGetPropertyName アクセサーに適用します。 set ではなく get に適用するのは、意外に思えるかもしれませんが、この規則により、シリアル化できる読み取り専用のアタッチ可能なメンバーの概念をサポートできます。これは、デザイナーのシナリオで役に立ちます。

SetPropertyName アクセサー

SetPropertyName アクセサーのシグネチャは次の形式にする必要があります。

public static void SetPropertyName(object target, object value)

  • 前のセクションで説明したものと同じロジックと結果を使用することで、実装でのより具体的な型として target オブジェクトを指定できます。

  • value オブジェクトは、実装のより具体的な型として指定することができます。

このメソッドへの値は、XAML で使用したときの入力であることに注意してください (通常は属性フォーム)。 属性フォームからの場合、テキスト構文に対する値コンバーターのサポートが必要であり、GetPropertyName アクセサーで属性を設定します。

アタッチ可能なメンバー ストア

通常、アタッチ可能なメンバーの値をオブジェクト グラフに格納したり、オブジェクト グラフから値を取得して適切にシリアル化したりするための手段を提供するのに、アクセサー メソッドでは十分ではありません。 この機能を提供するには、前のアクセサー シグネチャの target オブジェクトで値を格納できる必要があります。 ストレージ メカニズムは、アタッチ可能なメンバーがメンバー リストに含まれていないターゲットにメンバーをアタッチできるという、アタッチ可能なメンバーの原則と一致している必要があります。 .NET XAML サービスにより、API IAttachedPropertyStoreAttachablePropertyServices を通じて、アタッチ可能なメンバー ストアの実装手法が提供されます。 IAttachedPropertyStore は、XAML ライターによりストアの実装を検出するために使用され、アクセサーの target である型に実装されている必要があります。 静的な AttachablePropertyServices API は、アクセサーの本体内で使用され、その AttachableMemberIdentifier によってアタッチ可能なメンバーを参照します。

型、メンバー、アセンブリの属性を正しく設定することは、XAML の型システムから .NET XAML サービスに情報が報告されるために重要なことです。 XAML 型システムの情報の報告は、次のいずれかの状況が該当する場合に関連します。

  • .NET XAML サービスの XAML リーダーと XAML ライターに直接基づいている型を、XAML システムで使用する。
  • それらの XAML リーダーおよび XAML ライターに基づく XAML 利用フレームワークを定義または使用する。

カスタム型の XAML サポートに関連する各 XAML 関連の属性の一覧については、「カスタム型およびライブラリの XAML 関連の CLR 属性」を参照してください。

使用

カスタム型を使用するには、マークアップの作成者が、アセンブリのプレフィックスとカスタム型が含まれる CLR 名前空間をマップする必要があります。 この手順については、このトピックでは説明しません。

アクセス レベル

XAML により、internal アクセス レベルの型を読み込んでインスタンス化するための手段が提供されています。 この機能は、ユーザー コードで独自の型を定義し、同じユーザー コード スコープの一部であるマークアップからそれらのクラスをインスタンス化できるようにするために用意されています。

WPF の例は、UI の動作をリファクターする手段として意図されているが、public アクセス レベルでサポート クラスを宣言することによって暗黙的に指定される可能性がある拡張機能の一部としては意図されていない、UserControl をユーザー コードで定義する場合です。 それが XAML 型として参照されるのと同じアセンブリにバッキング コードがコンパイルされる場合は、そのような UserControlinternal アクセスで宣言できます。

完全な信頼で XAML を読み込んで XamlObjectWriter を使用するアプリケーションの場合、internal アクセス レベルでのクラスの読み込みは常に有効になります。

部分的な信頼で XAML を読み込むアプリケーションの場合は、XamlAccessLevel API を使用してアクセス レベルの特性を制御できます。 また、遅延メカニズム (WPF テンプレート システムなど) で、すべてのアクセス レベルのアクセス許可を伝達し、最終的な実行時の評価のためにそれらを保持できる必要があります。これは、XamlAccessLevel 情報を渡すことによって内部的に処理されます。

WPF の実装

WPF の XAML では、部分信頼アクセス モデルが使用されます。この場合、BAML が部分信頼で読み込まれると、BAML ソースであるアセンブリのアクセスは AssemblyAccessTo に制限されます。 遅延の場合、アクセス レベル情報を渡すメカニズムとして IXamlObjectWriterFactory.GetParentSettings が WPF により使用されます。

WPF の XAML の用語では、"内部型" とは参照元の XAML が含まれているのと同じアセンブリによって定義される型です。 そのような型は、xmlns:local="clr-namespace:WPFApplication1" のように、マッピングの assembly= 部分が意図的に除外された XAML 名前空間を使用してマップできます。 BAML で内部型が参照されていて、その型のアクセス レベルが internal である場合、アセンブリの GeneratedInternalTypeHelper クラスが生成されます。 GeneratedInternalTypeHelper を避ける必要がある場合は、public アクセス レベルを使用するか、関連するクラスを別のアセンブリに分離して、そのアセンブリに依存する必要があります。

関連項目