マークアップ拡張は、プリミティブまたは特定の XAML 型ではない値を取得するための XAML 手法です。 属性の使用において、マークアップ拡張は既知の文字列シーケンスである開始中かっこ {
を使用してマークアップ拡張スコープに入り、終了時には閉じ中かっこ }
を使用してスコープを抜けます。 .NET XAML サービスを使用する場合は、System.Xaml アセンブリから定義済みの XAML 言語マークアップ拡張機能の一部を使用できます。 System.Xaml で定義されている MarkupExtension クラスからサブクラス化し、独自のマークアップ拡張を定義することもできます。 または、そのフレームワークを既に参照している場合は、特定のフレームワークによって定義されたマークアップ拡張を使用できます。
マークアップ拡張機能の使用にアクセスすると、XAML オブジェクト ライターは、MarkupExtensionオーバーライドのサービス接続ポイントを介して、カスタム MarkupExtension.ProvideValue クラスにサービスを提供できます。 サービスを使用して、使用に関するコンテキスト、オブジェクト ライターの特定の機能、XAML スキーマ コンテキストなどを取得できます。
XAML で定義されたマークアップ拡張
XAML 言語のサポートのために、.NET XAML Services によっていくつかのマークアップ拡張機能が実装されています。 これらのマークアップ拡張は、言語としての XAML の仕様の一部に対応します。 これらは通常、一般的な使用法に示すように、構文の x:
プレフィックスによって識別できます。 これらの XAML 言語要素の .NET XAML サービスの実装はすべて、 MarkupExtension 基底クラスから派生します。
注
x:
プレフィックスは、XAML 運用環境のルート要素における XAML 言語名前空間の一般的な XAML 名前空間マッピングに使用されます。 たとえば、さまざまな特定のフレームワークの Visual Studio プロジェクトとページ テンプレートは、この x:
マッピングを使用して XAML ファイルを開始します。 独自の XAML 名前空間マッピングで別のプレフィックス トークンを選択することもできますが、このドキュメントでは、特定のフレームワークの既定の XAML 名前空間やその他の任意の CLR または XML 名前空間とは対照的に、XAML 言語 XAML 名前空間の定義された部分であるエンティティを識別する手段として、既定の x:
マッピングを想定しています。
x:Type
x:Type
は、名前付き型の Type オブジェクトを提供します。 この機能は、基になる CLR 型と型派生をグループ化モニカーまたは識別子として使用する遅延メカニズムで最も頻繁に使用されます。 WPF のスタイルとテンプレート、および TargetType
プロパティの使用方法は、具体的な例です。 詳細については、「 x:Type Markup Extension」を参照してください。
x:Static
x:Static
は、プロパティの値の型ではなく、その型に評価できる値型のコード エンティティから静的な値を生成します。 これは、型定義に既知の定数として既に存在する値を指定する場合に便利です。 詳細については、「 x:Static Markup Extension」を参照してください。
x:Null
x:Null
は、XAML メンバーの値として null
を指定します。 特定の型の設計や、より大きなフレームワークの概念によっては、 null
は常にプロパティの既定値、または空の文字列属性の暗黙的な値であるとは限りません。 詳細については、「 x:Null マークアップ拡張」を参照してください。
x:配列
x:Array
では、基本要素とコントロール モデルによって提供されるコレクションのサポートが意図的に使用されない場合に、XAML 構文での一般的な配列の作成がサポートされます。 詳細については、「 x:Array Markup Extension」を参照してください。 XAML 2009 では、配列は拡張機能ではなく言語プリミティブとしてアクセスされます。 詳細については、「 XAML 2009 言語機能」を参照してください。
x:参照
x:Reference
は、元の (2006) 言語セットの拡張機能である XAML 2009 の一部です。
x:Reference
は、オブジェクト グラフ内の別の既存のオブジェクトへの参照を表します。 そのオブジェクトは、その x:Name
によって識別されます。 詳細については、「 x:Reference Markup Extension」を参照してください。
その他の x: コンストラクト
XAML 言語機能をサポートする他の x:
コンストラクトが存在しますが、これらはマークアップ拡張機能として実装されていません。 詳細については、「XAML 名前空間 (x:) 言語機能の」を参照してください。
MarkupExtension 基本クラス
System.Xaml で XAML リーダーと XAML ライターの既定の実装と対話できるカスタム マークアップ拡張機能を定義するには、抽象 MarkupExtension クラスからクラスを派生させます。 そのクラスにはオーバーライドするメソッドが 1 つあり、 ProvideValue。 マークアップ拡張機能の使用に対する引数と一致する設定可能なプロパティをサポートするために、追加のコンストラクターを定義する必要がある場合もあります。
ProvideValueを通じて、カスタム マークアップ拡張機能は、XAML プロセッサによってマークアップ拡張機能が呼び出される環境を報告するサービス コンテキストにアクセスできます。 読み込みパスでは、これは通常、 XamlObjectWriterです。 保存パスでは、これは通常、 XamlXmlWriterです。 各サービス コンテキストは、サービス プロバイダー パターンを実装する内部 XAML サービス プロバイダー コンテキスト クラスとして報告します。 使用可能なサービスとその表現の詳細については、「 XAML の型コンバーターとマークアップ拡張」を参照してください。
マークアップ拡張クラスでは、パブリック アクセス レベルを使用する必要があります。XAML プロセッサは、サービスを使用するために、マークアップ拡張機能のサポート クラスを常にインスタンス化できる必要があります。
カスタム マークアップ拡張機能のサポートの種類の定義
.NET XAML サービス上に構築された .NET XAML サービスまたはフレームワークを使用する場合、マークアップ拡張機能のサポート型に名前を付ける方法には 2 つの選択肢があります。 型名は、XAML オブジェクト ライターが XAML でマークアップ拡張機能の使用を検出したときにマークアップ拡張機能サポート型にアクセスして呼び出す方法に関連します。 次のいずれかの名前付け方法を使用します。
- 型名に XAML マークアップ使用トークンと完全に一致するように名前を付けます。 たとえば、
{Collate ...}
拡張機能の使用をサポートするには、サポートの種類にCollate
名前を付けます。 - 使用文字列トークンにサフィックス
Extension
を加えた型名に名前を付けます。 たとえば、{Collate ...}
拡張機能の使用をサポートするには、サポートの種類にCollateExtension
名前を付けます。
検索の順序は、最初に Extension
サフィックスが付いたクラス名を検索してから、 Extension
サフィックスのないクラス名を探します。
マークアップ使用の観点から、使用法の一部として Extension
サフィックスを含めるのは有効です。 ただし、これは、 Extension
が本当にクラス名の一部であるかのように動作し、サポート クラスに Extension
サフィックスがない場合、XAML オブジェクト ライターは、その使用法のマークアップ拡張サポート クラスを解決できません。
パラメーターなしのコンストラクター
マークアップ拡張機能のすべてのサポート型について、パラメーターなしのパブリック コンストラクターを公開する必要があります。 XAML オブジェクト ライターがオブジェクト要素の使用からマークアップ拡張機能をインスタンス化する場合は、パラメーターなしのコンストラクターが必要です。 オブジェクト要素の使用をサポートすることは、マークアップ拡張機能 (特にシリアル化) に対する公平な期待です。 ただし、マークアップ拡張機能の属性の使用のみをサポートする場合は、パブリック コンストラクターなしでマークアップ拡張機能を実装できます。
マークアップ拡張機能の使用に引数がない場合は、パラメーターなしのコンストラクターが使用をサポートするために必要です。
カスタム マークアップ拡張機能のコンストラクター パターンと位置引数
目的の引数を使用するマークアップ拡張の場合、パブリック コンストラクターは、目的の使用法のモードに対応している必要があります。 言い換えると、マークアップ拡張機能が有効な使用法として 1 つの位置引数を必要とするように設計されている場合は、位置引数を受け取る 1 つの入力パラメーターを持つパブリック コンストラクターをサポートする必要があります。
たとえば、 Collate
マークアップ拡張は、そのモードを表す位置引数が 1 つあり、 CollationMode
列挙定数として指定されているモードのみをサポートするとします。 この場合、次の形式のコンストラクターが存在する必要があります。
public Collate(CollationMode collationMode) {...}
基本的なレベルでは、マークアップ拡張機能に渡される引数は、マークアップの属性値から転送されるため、文字列です。 すべての引数文字列を作成し、そのレベルで入力を操作できます。 ただし、マークアップ拡張引数がサポート クラスに渡される前に発生する特定の処理にアクセスできます。
この処理は、マークアップ拡張機能が作成されるオブジェクトであるかのように概念的に動作し、そのメンバー値が設定されます。 設定する各指定されたプロパティは、XAML の解析時に作成されたオブジェクトで指定されたメンバーを設定する方法と同様に評価されます。 次の 2 つの重要な違いがあります。
- 前に説明したように、マークアップ拡張機能のサポート型は、XAML でインスタンス化するためにパラメーターなしのコンストラクターを持つ必要はありません。 そのオブジェクトの構築は、テキスト構文で可能な引数がトークン化され、位置引数または名前付き引数として評価されるまで遅延され、その時点で適切なコンストラクターが呼び出されます。
- マークアップ拡張機能の使用は入れ子にすることができます。 最も内側のマークアップ拡張が最初に評価されます。 そのため、このような使用法を想定し、構築パラメーターの 1 つを、生成する値コンバーター (マークアップ拡張など) を必要とする型として宣言できます。
このような処理への依存を前の例に示しました。 .NET XAML Services XAML オブジェクト ライターは、列挙定数名をネイティブ レベルで列挙値に処理します。
マークアップ拡張位置指定パラメーターのテキスト構文の処理は、構築引数にある型に関連付けられている型コンバーターにも依存できます。
引数は位置引数と呼ばれます。これは、使用法でトークンが検出される順序が、割り当てられているコンストラクター パラメーターの位置順に対応するためです。 たとえば、次のコンストラクターシグネチャを考えてみましょう。
public Collate(CollationMode collationMode, object collateThis) {...}
XAML プロセッサでは、このマークアップ拡張機能に 2 つの位置引数が必要です。 使用 {Collate AlphaUp,{x:Reference circularFile}}
があった場合、 AlphaUp
トークンは最初のパラメーターに送信され、定数という名前の CollationMode
列挙体として評価されます。 内部 x:Reference
の結果が 2 番目のパラメーターに送信され、オブジェクトとして評価されます。
マークアップ拡張の構文と処理に関して XAML で指定された規則では、引数が位置引数か名前付き引数かにかかわらず、コンマは引数間の区切り記号です。
位置引数の重複アリティ
XAML オブジェクト ライターが位置指定引数でマークアップ拡張の使用を検出し、その数の引数 (重複するアリティ) を受け取る複数のコンストラクター引数がある場合、必ずしもエラーとは限りません。 動作は、カスタマイズ可能な XAML スキーマ コンテキスト設定 ( SupportMarkupExtensionsWithDuplicateArity) によって異なります。
SupportMarkupExtensionsWithDuplicateArityがtrue
の場合、XAML オブジェクト ライターは、アリティが重複しているという理由だけで例外をスローしてはいけません。 その時点を超える動作は厳密には定義されていません。 基本的な設計上の前提は、スキーマ コンテキストに特定のパラメーターに対して使用可能な型情報があり、重複する候補と一致する明示的なキャストを試行して、どのシグネチャが最適であるかを確認できることです。 特定のスキーマ コンテキスト内で実行されている XAML オブジェクト ライターが課すテストに合格できるシグネチャがない場合、例外が発生する可能性があります。
既定では、SupportMarkupExtensionsWithDuplicateArityは .NET XAML Services の CLR ベースのfalse
でXamlSchemaContextです。 したがって、既定の XamlObjectWriter は、バックエンド型のコンストラクターにアリティの重複があるマークアップ拡張機能の使用が発生した場合に例外をスローします。
カスタム マークアップ拡張機能の名前付き引数
XAML で指定されたマークアップ拡張では、名前付き引数フォームを使用して使用することもできます。 トークン化の最初のレベルでは、テキスト構文は引数に分割されます。 引数内に等号 (=) が存在すると、引数が名前付き引数として識別されます。 このような引数は名前と値のペアに分割(トークン化)されます。 この場合の名前は、マークアップ拡張のサポート型における公開設定可能プロパティを示します。 名前付き引数の使用をサポートする場合は、これらのパブリック設定可能なプロパティを指定する必要があります。 プロパティは公開のままであれば継承可能です。
マークアップ拡張機能の実装からサービス プロバイダー コンテキストにアクセスする
使用可能なサービスは、どの値コンバーターでも同じです。 違いは、各値コンバーターがサービス コンテキストを受け取る方法です。 利用可能なサービスへのアクセスについては、 XAML の型コンバーターとマークアップ拡張に関するトピックを参照してください。
マークアップ拡張機能のプロパティ要素の使用方法
マークアップ拡張機能の使用シナリオは、多くの場合、属性の使用でマークアップ拡張機能を使用するように設計されています。 ただし、プロパティ要素の使用をサポートするためにバッキング クラスを定義することもできます。
マークアップ拡張機能のプロパティ要素の使用をサポートするには、パラメーターなしのパブリック コンストラクターを定義します。 これは、静的コンストラクターではなくインスタンス コンストラクターである必要があります。 これは、XAML プロセッサは通常、マークアップから処理するすべてのオブジェクト要素に対してパラメーターなしのコンストラクターを呼び出す必要があり、これにはオブジェクト要素としてマークアップ拡張クラスが含まれているために必要です。 高度なシナリオでは、クラスの既定以外の構築パスを定義できます。 (詳細については、 x:FactoryMethod ディレクティブを参照してください。ただし、マークアップ拡張の目的でこれらのパターンを使用しないでください。これは、デザイナーと生のマークアップのユーザーの両方で、使用パターンの検出がはるかに困難になるためです。
カスタム マークアップ拡張機能の属性付け
設計環境と特定の XAML オブジェクト ライター シナリオの両方をサポートするには、いくつかの CLR 属性を持つマークアップ拡張機能のサポート型を属性化する必要があります。 これらの属性は、目的のマークアップ拡張機能の使用状況を報告します。
MarkupExtensionReturnTypeAttributeは、Type返されるオブジェクト型のProvideValue情報を報告します。 その純粋なシグネチャによって、 ProvideValue は Objectを返します。 しかし、さまざまなコンシューマーが、より正確な戻り値の型情報を必要とすることがあります。 これには次のものが含まれます。
- デザイナーと IDE。マークアップ拡張機能の使用に対して型対応のサポートを提供できる可能性があります。
- ターゲット クラスに対する
SetMarkupExtension
ハンドラーの高度な実装。これは、名前によって特定の既知の MarkupExtension 実装に分岐するのではなく、リフレクションに依存してマークアップ拡張機能の戻り値の型を決定する場合があります。
マークアップ拡張機能の使用法のシリアル化
XAML オブジェクト ライターがマークアップ拡張機能の使用を処理し、 ProvideValueを呼び出すと、以前はマークアップ拡張機能の使用であるコンテキストが XAML ノード ストリームに保持されますが、オブジェクト グラフには保持されません。 オブジェクト グラフでは、値のみが保持されます。 元のマークアップ拡張機能の使用をシリアル化された出力に保持する設計シナリオまたはその他の理由がある場合は、ロード パス XAML ノード ストリームからマークアップ拡張機能の使用状況を追跡するための独自のインフラストラクチャを設計する必要があります。 ノード ストリームの要素を読み込みパスから再作成し、保存パスでシリアル化するために XAML ライターに再生する動作を実装し、ノード ストリームの適切な位置の値に置き換えることができます。
XAML ノード ストリームのマークアップ拡張
読み込みパスで XAML ノード ストリームを使用している場合は、マークアップ拡張機能の使用がノード ストリームにオブジェクトとして表示されます。
マークアップ拡張の使用法で位置引数を使用する場合、初期化値を持つ開始オブジェクトとして表されます。 大まかなテキスト表現として、ノード ストリームは次のようになります。
StartObject
(XamlType はマークアップ拡張機能の定義型であり、戻り値の型ではありません)
StartMember
( XamlMember の名前は _InitializationText
)
Value
(値は、中間の区切り記号を含む文字列としての位置引数です)
EndMember
EndObject
名前付き引数を使用したマークアップ拡張の使用法は、関連する名前のメンバーを持つオブジェクトとして表され、各セットにはテキスト文字列値が設定されます。
マークアップ拡張機能の ProvideValue
実装を実際に呼び出すには、型マッピングとマークアップ拡張機能の作成で型インスタンスをサポートする必要があるため、XAML スキーマ コンテキストが必要です。 これは、マークアップ拡張機能の使用が既定の .NET XAML サービス ノード ストリームでこのように保持される理由の 1 つです。多くの場合、読み込みパスのリーダー部分には必要な XAML スキーマ コンテキストが使用できません。
保存パスで XAML ノード ストリームを操作している場合、通常、シリアル化するオブジェクトがマークアップ拡張の使用と ProvideValue
結果によって提供されたことを通知できるオブジェクト グラフ表現には何も存在しません。 ラウンドトリップのためにマークアップ拡張機能の使用を保持し、オブジェクト グラフ内の他の変更もキャプチャする必要があるシナリオでは、元の XAML 入力からマークアップ拡張機能の使用に関する知識を保持するための独自の手法を考案する必要があります。 たとえば、マークアップ拡張機能の使用法を復元するには、マークアップ拡張機能の使用を復元したり、元の XAML とラウンドトリップ XAML の間で何らかの種類のマージを実行したりするために、保存パスのノード ストリームを操作する必要がある場合があります。 WPF などの一部の XAML 実装フレームワークでは、中間型 (式) を使用して、マークアップ拡張機能の使用によって値が提供されたケースを表すのに役立ちます。
こちらも参照ください
- MarkupExtension
- XAML の
型コンバーターとマークアップ拡張 - マークアップ拡張機能と WPF XAML
.NET Desktop feedback