.NET XAML サービスで使用するカスタム型を定義する
ビジネス オブジェクトまたは特定のフレームワークに依存しない型であるカスタム型を定義する場合は、XAML の特定のベスト プラクティスに従うことができます。 これらのプラクティスに従うと、.NET XAML Services とその XAML リーダーと XAML ライターは、型の XAML 特性を検出し、XAML 型システムを使用して XAML ノード ストリーム内で適切な表現を提供できます。 このトピックでは、型定義、メンバー定義、および型またはメンバーの CLR 属性のベスト プラクティスについて説明します。
XAML のコンストラクター パターンと型定義
XAML でオブジェクト要素としてインスタンス化するには、カスタム クラスが次の要件を満たしている必要があります。
カスタム クラスはパブリックである必要があり、パラメーターなしのパブリック コンストラクターを公開する必要があります。 (構造に関する注意事項については、次のセクションを参照してください)。
カスタム クラスは入れ子になったクラスにすることはできません。 完全名パスの余分な "dot" は、クラス名前空間の除算をあいまいにし、添付プロパティなどの他の XAML 機能と干渉します。 オブジェクトをオブジェクト要素としてインスタンス化できる場合、作成されたオブジェクトは、そのオブジェクトを基になる型として受け取る任意のプロパティのプロパティ要素フォームに入力できます。
値コンバーターを有効にした場合でも、これらの条件を満たさない型のオブジェクト値を指定できます。 詳細については、「型コンバーターと XAMLのマークアップ拡張」を参照してください。
構造
構造体は、CLR 定義によって XAML で常に構築できます。 これは、CLR コンパイラが構造体のパラメーターなしのコンストラクターを暗黙的に作成するためです。 このコンストラクターは、すべてのプロパティ値を既定値に初期化します。
場合によっては、構造体の既定の構築動作は望ましくありません。 これは、構造体が値を埋め、概念的に共用体として機能することを目的としているためである可能性があります。 和集合として、含まれる値は相互に排他的な解釈を持つ可能性があるため、そのプロパティのいずれも設定できません。 WPF ボキャブラリのこのような構造の例は、GridLengthです。 このような構造体では、構造値のさまざまな解釈またはモードを作成する文字列規則を使用して、値を属性形式で表すことができるように、型コンバーターを実装する必要があります。 この構造体では、パラメーターなしのコンストラクターを使用したコード構築でも同様の動作を公開する必要があります。
インターフェイス
インターフェイスは、基になるメンバーの型として使用できます。 XAML 型システムは、割り当て可能なリストをチェックし、値として指定されたオブジェクトをインターフェイスに割り当てることができることを想定しています。 関連する割り当て可能な型が XAML 構築要件をサポートしている限り、インターフェイスを XAML 型として表示する方法の概念はありません。
Factory メソッド
ファクトリ メソッドは 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 型システムは、IsReadPublic や IsWritePublicなどの XamlMember プロパティに対して提供される適切な情報を持つプロパティをメンバーとして報告できます。
特定のプロパティでは、TypeConverterAttributeを適用することでテキスト構文を有効にすることができます。 詳細については、「型コンバーターと XAMLのマークアップ拡張」を参照してください。
テキスト構文またはネイティブ XAML 変換が存在しない場合や、マークアップ拡張の使用法などの間接参照がない場合、プロパティの型 (XAML 型システムのTargetType) は、ターゲットの型を CLR 型として扱うことで、XAML オブジェクト ライターにインスタンスを返すことができる必要があります。
XAML 2009 を使用している場合は、x:Reference Markup Extension を使用して、前の考慮事項が満たされていない場合に値を指定できます。ただし、これは型定義の問題よりも使用上の問題です。
イベント
イベントをパブリック CLR イベントとして定義する場合、XAML 型システムは、true
として IsEvent を持つメンバーとしてイベントを報告できます。 イベント ハンドラーの配線は、.NET XAML サービス機能のスコープ内にありません。配線は、特定のフレームワークと実装に任されています。
メソッド
メソッドのインライン コードは、既定の XAML 機能ではありません。 ほとんどの場合、XAML からメソッド メンバーを直接参照する必要はありません。XAML のメソッドの役割は、特定の XAML パターンのサポートを提供することだけです。 x:FactoryMethod ディレクティブ は例外です。
田畑
CLR の設計ガイドラインでは、非静的フィールドは推奨されません。 静的フィールドの場合は、
Attachable メンバー
アタッチ可能なメンバーは、定義型のアクセサー メソッド パターンを介して XAML に公開されます。 定義する型自体は、オブジェクトとして XAML で使用できる必要はありません。 実際、一般的なパターンは、アタッチ可能なメンバーを所有し、関連する動作を実装する役割を持つサービス クラスを宣言することですが、UI 表現などの他の機能は提供しません。 以降のセクションでは、PropertyName
これらのパターンと型の他のメソッド間の名前の競合には注意してください。 いずれかのパターンに一致するメンバーが存在する場合は、意図していなくても、XAML プロセッサによってアタッチ可能なメンバー使用経路として解釈できます。
GetPropertyName アクセサー
GetPropertyName
アクセサーの署名は次の値にする必要があります。
public static object GetPropertyName(object target)
target
オブジェクトは、実装でより具体的な型として指定できます。 これを使用して、アタッチ可能なメンバーの使用範囲を指定できます。目的のスコープ外の使用法では、無効なキャスト例外がスローされ、XAML 解析エラーによって表示されます。 パラメーター名target
は必須ではありませんが、ほとんどの実装では規則によってtarget
という名前が付けられています。戻り値は、実装でより具体的な型として指定できます。
アタッチ可能なメンバーの属性を使用するための TypeConverter 有効なテキスト構文をサポートするには、GetPropertyName
アクセサーに TypeConverterAttribute を適用します。
set
の代わりに get
に適用することは直感的ではないようです。ただし、この規則では、シリアル化可能な読み取り専用のアタッチ可能なメンバーの概念をサポートできます。これは、デザイナーのシナリオで役立ちます。
SetPropertyName アクセサー
SetPropertyName
アクセサーの署名は次の値にする必要があります。
public static void SetPropertyName(object target, object value)
target
オブジェクトは、前のセクションで説明したのと同じロジックと結果を使用して、実装でより具体的な型として指定できます。value
オブジェクトは、実装でより具体的な型として指定できます。
このメソッドの値は、XAML の使用法 (通常は属性形式) からの入力であることを覚えておいてください。 属性フォームでは、テキスト構文に対する値コンバーターのサポートが必要であり、GetPropertyName
アクセサーで属性を指定する必要があります。
アタッチ可能なメンバー ストア
アクセサー メソッドは通常、アタッチ可能なメンバー値をオブジェクト グラフに配置したり、オブジェクト グラフから値を取得して適切にシリアル化したりする手段を提供するのに十分ではありません。 この機能を提供するには、前のアクセサー署名の target
オブジェクトが値を格納できる必要があります。 ストレージ メカニズムは、アタッチ可能なメンバーがメンバー リストにないターゲットにメンバーがアタッチ可能であるというアタッチ可能なメンバーの原則と一致している必要があります。 .NET XAML サービスは、API IAttachedPropertyStore と AttachablePropertyServicesを介してアタッチ可能なメンバー ストアの実装手法を提供します。
IAttachedPropertyStore は XAML ライターによってストアの実装を検出するために使用され、アクセサーの target
である型に実装する必要があります。 静的 AttachablePropertyServices API はアクセサーの本体内で使用され、AttachableMemberIdentifierによってアタッチ可能なメンバーを参照します。
XAML-Related CLR 属性
XAML 型システム情報を .NET XAML サービスに報告するには、型、メンバー、アセンブリを正しく属性付けすることが重要です。 XAML 型システム情報のレポートは、次のいずれかの状況が該当する場合に関連します。
- .NET XAML Services XAML リーダーと XAML ライターに直接基づく XAML システムで型を使用する予定です。
- これらの XAML リーダーと XAML ライターに基づく XAML を利用するフレームワークを定義または使用します。
カスタム型の XAML サポートに関連する各 XAML 関連属性の一覧については、「カスタム型とライブラリの CLR 属性 XAML-Related」を参照してください。
使い
カスタム型を使用するには、マークアップ作成者がカスタム型を含むアセンブリと CLR 名前空間のプレフィックスをマップする必要があります。 この手順については、このトピックでは説明しません。
アクセス レベル
XAML には、internal
アクセス レベルを持つ型を読み込んでインスタンス化する手段が用意されています。 この機能は、ユーザー コードが独自の型を定義し、同じユーザー コード スコープの一部でもあるマークアップからそれらのクラスをインスタンス化できるように提供されます。
WPF の例は、ユーザー コードが UI の動作をリファクタリングする方法として意図された UserControl を定義する場合であり、サポート クラスを public
アクセス レベルで宣言することによって暗黙的に示される可能性のある拡張メカニズムの一部ではありません。 このような UserControl は、バッキング コードが XAML 型として参照されているのと同じアセンブリにコンパイルされる場合、internal
アクセスを使用して宣言できます。
完全な信頼の下で XAML を読み込み、XamlObjectWriterを使用するアプリケーションでは、internal
アクセス レベルを持つクラスの読み込みは常に有効になります。
部分信頼の下で XAML を読み込むアプリケーションでは、XamlAccessLevel API を使用してアクセス レベルの特性を制御できます。 また、遅延メカニズム (WPF テンプレート システムなど) は、アクセス レベルのアクセス許可を伝達し、最終的な実行時の評価のために保持できる必要があります。これは、XamlAccessLevel 情報を渡すことによって内部的に処理されます。
WPF の実装
WPF XAML は部分信頼アクセス モデルを使用します。このモデルでは、BAML が部分信頼で読み込まれる場合、アクセスは BAML ソースであるアセンブリの AssemblyAccessTo に制限されます。 遅延の場合、WPF はアクセス レベル情報を渡すためのメカニズムとして IXamlObjectWriterFactory.GetParentSettings を使用します。
WPF XAML の用語では、内部型 は、参照元の XAML も含む同じアセンブリによって定義される型です。 このような型は、マッピングの assembly= 部分 (たとえば、xmlns:local="clr-namespace:WPFApplication1"
) を意図的に省略する XAML 名前空間を介してマップできます。 BAML が内部型を参照し、その型がアクセス レベル internal
場合、アセンブリの GeneratedInternalTypeHelper
クラスが生成されます。
GeneratedInternalTypeHelper
を回避する場合は、public
アクセス レベルを使用するか、関連するクラスを別のアセンブリに組み込み、そのアセンブリを依存させる必要があります。
関連項目
- カスタム型とライブラリの CLR 属性の XAML-Related
- XAML サービス の
.NET Desktop feedback