次の方法で共有


WPF の XAML クラスとカスタム クラス

共通言語ランタイム (CLR) フレームワークに実装されている XAML では、任意の共通言語ランタイム (CLR) 言語でカスタム クラスまたは構造体を定義し、XAML マークアップを使用してそのクラスにアクセスする機能がサポートされています。 Windows Presentation Foundation (WPF) で定義された型と、同じマークアップ ファイル内のカスタム型を組み合わせて使用できます。通常は、カスタム型を XAML 名前空間プレフィックスにマッピングします。 このトピックでは、カスタム クラスが XAML 要素として使用できるようにするために満たす必要がある要件について説明します。

アプリケーションまたはアセンブリのカスタム クラス

XAML で使用されるカスタム クラスは、分離コード内、またはプライマリ Windows Presentation Foundation (WPF) アプリケーションを生成する他のコード内、またはクラス ライブラリとして使用される実行可能ファイルや DLL などの別のアセンブリ内のクラスとして、2 つの異なる方法で定義できます。 これらのアプローチにはそれぞれ、特定の長所と短所があります。

  • クラス ライブラリを作成する利点は、このようなカスタム クラスをさまざまなアプリケーション間で共有できることです。 また、別のライブラリを使用すると、アプリケーションのバージョン管理の問題を制御しやすくなり、XAML ページのルート要素として目的のクラスを使用するクラスを簡単に作成できます。

  • アプリケーションでカスタム クラスを定義する利点は、この手法が比較的軽量であり、メイン アプリケーション実行可能ファイル以外に個別のアセンブリを導入するときに発生するデプロイとテストの問題を最小限に抑える点です。

  • 同じアセンブリでも異なるアセンブリでも、XAML で要素として使用するには、カスタム クラスを CLR 名前空間と XML 名前空間の間でマップする必要があります。 WPF XAMLの XAML 名前空間と名前空間マッピングの を参照してください。

XAML 要素としてのカスタム クラスの要件

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

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

  • カスタムクラスは入れ子クラスにしてはいけません。 入れ子になったクラスとその一般的な CLR 使用法構文の "dot" は、他の WPF や XAML の機能 (添付プロパティなど) と干渉します。

オブジェクト要素の構文を有効にするだけでなく、オブジェクト定義では、そのオブジェクトを値型として受け取る他のパブリック プロパティのプロパティ要素構文も有効になります。 これは、オブジェクト要素としてインスタンス化されたオブジェクトが、そのようなプロパティのプロパティ要素値を埋めることができるためです。

構造

カスタム型として定義する構造体は、WPF の XAML で常に構築できます。これは、CLR コンパイラが、すべてのプロパティ値を既定値に初期化する構造体のパラメーターなしのコンストラクターを暗黙的に作成するためです。 場合によっては、構造体の既定の構築動作やオブジェクト要素の使用は望ましくありません。 これは、構造体が値を埋め、概念的に共用体として機能することを目的としているためです。この場合、含まれる値は相互に排他的な解釈を持つ可能性があるため、そのプロパティは設定できません。 このような構造体の WPF の例は、GridLengthです。 一般に、このような構造体は、構造体の値のさまざまな解釈またはモードを作成する文字列規則を使用して、値を属性形式で表現できるように型コンバーターを実装する必要があります。 この構造体では、パラメーターなしのコンストラクターを使用したコード構築でも同様の動作を公開する必要があります。

XAML 属性としてのカスタム クラスのプロパティの要件

プロパティは、値渡し型 (プリミティブなど) を参照するか、XAML プロセッサがアクセスできるパラメーターなしのコンストラクターまたは専用型コンバーターを持つ型のクラスを使用する必要があります。 CLR XAML 実装では、XAML プロセッサは、言語プリミティブのネイティブ サポートを通じて、またはバッキング型定義の型またはメンバーに TypeConverterAttribute を適用して、このようなコンバーターを見つけます。

または、このプロパティは抽象クラス型またはインターフェイスを参照できます。 抽象クラスまたはインターフェイスの場合、XAML 解析の期待値は、インターフェイスを実装する具象クラス インスタンス、または抽象クラスから派生した型のインスタンスでプロパティ値を埋める必要があるということです。

プロパティは抽象クラスで宣言できますが、抽象クラスから派生した具象クラスでのみ設定できます。 これは、クラスのオブジェクト要素を作成するには、クラスに対するパブリック パラメーターなしのコンストラクターが必要であるためです。

TypeConverter Enabled 属性の構文

クラス レベルで専用の属性付き型コンバーターを指定した場合、適用された型変換により、その型をインスタンス化する必要があるプロパティの属性構文が有効になります。 型コンバーターでは、型のオブジェクト要素の使用は有効になりません。オブジェクト要素の使用を有効にできるのは、その型にパラメーターなしのコンストラクターが存在することだけです。 したがって、型コンバーターが有効になっているプロパティは、通常、型自体がオブジェクト要素構文もサポートしていない限り、プロパティ構文では使用できません。 例外は、プロパティ要素の構文を指定できますが、プロパティ要素に文字列が含まれていることです。 この使用法は基本的に属性構文の使用法と同等であり、属性値のより堅牢な空白処理が必要でない限り、このような使用法は一般的ではありません。 たとえば、文字列を受け取るプロパティ要素の使用法と、属性の使用法は同等です。

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

属性構文が許可されているが、オブジェクト要素を含むプロパティ要素構文が XAML によって許可されないプロパティの例は、Cursor 型を受け取るさまざまなプロパティです。 Cursor クラスには専用の型コンバーター CursorConverterがありますが、パラメーターなしのコンストラクターは公開されないため、実際の Cursor 型が参照型であっても、Cursor プロパティは属性構文でのみ設定できます。

Per-Property 型コンバーター

または、プロパティ自体がプロパティ レベルで型コンバーターを宣言することもできます。 これにより、属性の入力文字列値を適切な型に基づく ConvertFrom 操作の入力として処理することにより、プロパティの型のオブジェクトをインラインでインスタンス化する "ミニ言語" が有効になります。 通常、これは便利なアクセサーを提供するために行われます。XAML でプロパティの設定を有効にする唯一の手段ではありません。 ただし、パラメーターなしのコンストラクターまたは属性付き型コンバーターを提供しない既存の CLR 型を使用する属性には、型コンバーターを使用することもできます。 WPF API の例としては、CultureInfo 型を受け取る特定のプロパティがあります。 この場合、WPF は、以前のバージョンのフレームワークで使用されていた互換性と移行のシナリオに対応するために既存の Microsoft .NET Framework CultureInfo 型を使用しましたが、CultureInfo 型では、XAML プロパティ値として直接使用するために必要なコンストラクターまたは型レベルの型変換はサポートされていませんでした。

XAML を使用するプロパティを公開する場合 (特にコントロール作成者の場合)、依存関係プロパティを使用してそのプロパティをバッキングすることを強くお勧めします。 これは、XAML プロセッサの既存の Windows Presentation Foundation (WPF) 実装を使用する場合に特に当てはまります。これは、DependencyProperty バッキングを使用してパフォーマンスを向上させることができるためです。 依存関係プロパティは、ユーザーが XAML アクセス可能なプロパティに期待するプロパティのプロパティ システム機能を公開します。 これには、アニメーション、データ バインディング、スタイルのサポートなどの機能が含まれます。 詳細については、「カスタム依存関係プロパティ 」と「XAML の読み込みと依存関係プロパティ 」を参照してください。

型コンバーターの書き込みと属性付け

場合によっては、プロパティ型の型変換を提供するために、カスタム TypeConverter 派生クラスを記述する必要があります。 XAML の使用法をサポートできる型コンバーターを派生および作成する方法や、を適用する方法については、「TypeConverters and XAML」および「」を参照してください。

カスタム クラスのイベントに対する XAML イベント ハンドラー属性構文の要件

CLR イベントとして使用できるようにするには、パラメーターなしのコンストラクターをサポートするクラス、または派生クラスでイベントにアクセスできる抽象クラスで、イベントをパブリック イベントとして公開する必要があります。 ルーティング イベントとして便利に使用するには、CLR イベントに明示的な add メソッドと remove メソッドを実装する必要があります。このメソッドは、CLR イベント シグネチャのハンドラーを追加および削除し、それらのハンドラーを AddHandler メソッドと RemoveHandler メソッドに転送します。 これらのメソッドは、イベントがアタッチされているインスタンスのルーティング イベント ハンドラー ストアにハンドラーを追加または削除します。

手記

AddHandlerを使用してルーティング イベントのハンドラーを直接登録したり、ルーティング イベントを公開する CLR イベントを意図的に定義したりすることはできません。 これは、イベントでハンドラーをアタッチするための XAML 属性構文が有効にならず、結果としてその型の機能がXAMLからはあまり明確に見えなくなるため、一般的には推奨されません。

コレクションプロパティの書き込み

コレクション型を受け取るプロパティには、コレクションに追加されるオブジェクトを指定できる XAML 構文があります。 この構文には、2 つの注目すべき機能があります。

  • コレクション オブジェクトであるオブジェクトは、オブジェクト要素の構文で指定する必要はありません。 コレクション型を受け取る XAML でプロパティを指定するたびに、そのコレクション型の存在は暗黙的です。

  • マークアップ内のコレクション プロパティの子要素は、コレクションのメンバーになるように処理されます。 通常、コレクションのメンバーへのコード アクセスは、Addなどのリスト/ディクショナリ メソッド、またはインデクサーを介して実行されます。 ただし、XAML 構文はメソッドやインデクサーをサポートしていません (例外: XAML 2009 ではメソッドをサポートできますが、XAML 2009 を使用すると、可能な WPF の使用が制限されます。XAML 2009 言語機能参照)。 コレクションは明らかに要素のツリーを構築するための非常に一般的な要件であり、宣言型 XAML でこれらのコレクションを設定する何らかの方法が必要です。 したがって、コレクション プロパティの子要素は、コレクション プロパティ型の値であるコレクションに追加することによって処理されます。

.NET Framework XAML サービスの実装、したがって、WPF XAML プロセッサは、コレクション プロパティを構成するものに対して次の定義を使用します。 プロパティのプロパティ型は、次のいずれかを実装する必要があります。

  • IListを実装します。

  • IDictionaryを実装します。

  • Array から派生します (XAML の配列の詳細については、「x:Array Markup Extension」を参照してください)。

  • IAddChild (WPF によって定義されたインターフェイス) を実装します。

CLR のこれらの各型には Add メソッドがあります。これは、オブジェクト グラフの作成時に XAML プロセッサによって基になるコレクションに項目を追加するために使用されます。

手記

汎用 List インターフェイスと Dictionary インターフェイス (IList<T> および IDictionary<TKey,TValue>) は、WPF XAML プロセッサによるコレクション検出ではサポートされていません。 ただし、List<T> クラスは基底クラスとして使用できます。これは、IList を直接実装するため、または基底クラスとして Dictionary<TKey,TValue> するためです。これは、IDictionary を直接実装するためです。

コレクションを受け取るプロパティを宣言するときは、そのプロパティ値が型の新しいインスタンスでどのように初期化されるかに注意してください。 プロパティを依存関係プロパティとして実装していない場合は、コレクション型コンストラクターを呼び出すバッキング フィールドを使用するプロパティを使用すれば十分です。 プロパティが依存関係プロパティの場合は、既定の型コンストラクターの一部としてコレクション プロパティを初期化する必要があります。 これは、依存関係プロパティはメタデータから既定値を受け取り、通常はコレクション プロパティの初期値を静的な共有コレクションにしたくないためです。 各包含型インスタンスごとにコレクション インスタンスが存在する必要があります。 詳細については、「カスタム依存関係プロパティ 」を参照してください。

コレクション プロパティのカスタム コレクション型を実装できます。 暗黙的なコレクション プロパティの処理のため、カスタム コレクション型は、XAML で暗黙的に使用するためにパラメーターなしのコンストラクターを提供する必要はありません。 ただし、必要に応じて、コレクション型のパラメーターなしのコンストラクターを指定できます。 これは価値のある練習になる可能性があります。 パラメーターなしのコンストラクターを指定しない限り、コレクションをオブジェクト要素として明示的に宣言することはできません。 一部のマークアップ作成者は、マークアップ スタイルの問題として明示的なコレクションを参照することを好む場合があります。 また、パラメーターなしのコンストラクターを使用すると、コレクション型をプロパティ値として使用する新しいオブジェクトを作成するときに、初期化要件を簡略化できます。

XAML コンテンツ プロパティの宣言

XAML 言語は、XAML コンテンツ プロパティの概念を定義します。 オブジェクト構文で使用できる各クラスには、XAML コンテンツ プロパティを 1 つだけ指定できます。 プロパティをクラスの XAML コンテンツ プロパティとして宣言するには、クラス定義の一部として ContentPropertyAttribute を適用します。 目的の XAML コンテンツ プロパティの名前を属性の Name として指定します。 プロパティは、PropertyInfoなどのリフレクションコンストラクトとしてではなく、名前で文字列として指定されます。

コレクション プロパティを XAML コンテンツ プロパティとして指定できます。 これにより、そのプロパティが使用されます。これにより、オブジェクト要素は、コレクション オブジェクト要素またはプロパティ要素タグを介在させることなく、1 つ以上の子要素を持つことができます。 これらの要素は、XAML コンテンツ プロパティの値として扱われ、バッキング コレクション インスタンスに追加されます。

一部の既存の XAML コンテンツ プロパティでは、Objectのプロパティ型を使用します。 これにより、単一の参照オブジェクト値を取得するだけでなく、String などのプリミティブ値を受け取ることができる XAML コンテンツ プロパティが有効になります。 このモデルに従う場合、型の決定と可能な型の処理はあなたの型の責任になります。 Object コンテンツ タイプの一般的な理由は、オブジェクト コンテンツを文字列として追加する簡単な方法 (既定のプレゼンテーション処理を受け取る) と、既定以外のプレゼンテーションまたは追加データを指定するオブジェクト コンテンツを追加する高度な方法の両方をサポートすることです。

XAML のシリアル化

コントロール作成者の場合など、特定のシナリオでは、XAML でインスタンス化できるオブジェクト表現を、同等の XAML マークアップにシリアル化し直すこともできます。 シリアル化の要件については、このトピックでは説明しません。 コントロール作成の概要要素ツリーとシリアル化を参照してください。

関連項目