次の方法で共有


マークアップ拡張機能と WPF XAML

このトピックでは、XAML のマークアップ拡張の概念 (構文規則、目的、基になるクラス オブジェクト モデルなど) について説明します。 マークアップ拡張は、XAML 言語と XAML サービスの .NET 実装の一般的な機能です。 このトピックでは、WPF XAML で使用するためのマークアップ拡張機能について具体的に説明します。

XAML プロセッサとマークアップ拡張機能

一般に、XAML パーサーは、属性値をプリミティブに変換できるリテラル文字列として解釈するか、何らかの方法でオブジェクトに変換することができます。 そのような手段の 1 つは、型コンバーターを参照する方法です。これは、TypeConverters と XAMLトピックに記載されています。 ただし、異なる動作が必要なシナリオもあります。 たとえば、XAML プロセッサは、属性の値がオブジェクト グラフ内の新しいオブジェクトになることがないように指示できます。 代わりに、この属性は、グラフの別の部分で既に構築されているオブジェクトまたは静的オブジェクトへの参照を作成するオブジェクト グラフになります。 もう 1 つのシナリオは、オブジェクトのコンストラクターに既定以外の引数を提供する構文を使用するように XAML プロセッサに指示できることです。 これらは、マークアップ拡張機能がソリューションを提供できるシナリオの種類です。

基本的なマークアップ拡張構文

マークアップ拡張を実装して、属性使用法のプロパティ、プロパティ要素のプロパティ、またはその両方の値を提供できます。

属性値を指定するために使用する場合、マークアップ拡張シーケンスを XAML プロセッサに区別する構文は、開始中かっこと終了中かっこ ({ と }) の存在です。 マークアップ拡張の型は、開き中括弧の直後の文字列トークンによって識別されます。

プロパティ要素の構文で使用する場合、マークアップ拡張は、プロパティ要素の値を提供するために使用される他の要素と視覚的に同じです。マークアップ拡張クラスを要素として参照する XAML 要素宣言は、山かっこ (<>) で囲まれています。

XAML-Defined マークアップ拡張機能

XAML の WPF 実装に固有ではなく、言語としての XAML の組み込みまたは機能の実装であるマークアップ拡張がいくつか存在します。 これらのマークアップ拡張機能は、一般的な .NET Framework XAML サービスの一部として System.Xaml アセンブリに実装され、XAML 言語 XAML 名前空間内にあります。 一般的なマークアップの使用に関しては、通常、これらのマークアップ拡張機能は、使用法の x: プレフィックスによって識別できます。 MarkupExtension 基本クラス (System.Xaml でも定義) は、XAML リーダーと XAML ライター (WPF XAML を含む) でサポートされるためにすべてのマークアップ拡張機能を使用する必要があるパターンを提供します。

  • x:Type は、名前付き型の Type オブジェクトを提供します。 この機能は、スタイルとテンプレートで最も頻繁に使用されます。 詳細については、「x:Type Markup Extensionを参照してください。

  • x:Static は静的な値を生成します。 値は、ターゲット プロパティの値の型ではなく、その型に変換できる値型コード エンティティから取得されます。 詳細については、「x:Static Markup Extensionを参照してください。

  • x:Null プロパティの値として null を指定し、属性またはプロパティ要素の値に使用できます。 詳細については、「x:Null マークアップ拡張」を参照してください。

  • x:Array は、WPF 基本要素とコントロール モデルによって提供されるコレクションのサポートが意図的に使用されない場合に、XAML 構文で一般的な配列を作成するためのサポートを提供します。 詳細については、「x:Array Markup Extensionを参照してください。

手記

x: プレフィックスは、XAML ファイルまたは運用環境のルート要素で、XAML 言語組み込みの一般的な XAML 名前空間マッピングに使用されます。 たとえば、WPF アプリケーション用の Visual Studio テンプレートは、この x: マッピングを使用して XAML ファイルを開始します。 独自の XAML 名前空間マッピングで別のプレフィックス トークンを選択することもできますが、このドキュメントでは、WPF の既定の名前空間や、特定のフレームワークに関連しない他の XAML 名前空間ではなく、XAML 言語の XAML 名前空間の定義された部分であるエンティティを識別する手段として、既定の x: マッピングを想定しています。

WPF-Specific マークアップ拡張機能

WPF プログラミングで使用される最も一般的なマークアップ拡張機能は、リソース参照 (StaticResourceDynamicResource) をサポートするマークアップ拡張機能と、データ バインディング (Binding) をサポートするマークアップ拡張機能です。

  • StaticResource は、既に定義されているリソースの値を置き換えることで、プロパティの値を提供します。 StaticResource 評価は最終的に XAML 読み込み時に行われ、実行時にオブジェクト グラフにアクセスすることはできません。 詳細については、StaticResource Markup Extensionを参照してください。

  • DynamicResource は、その値をリソースへの実行時参照として遅延することによって、プロパティの値を提供します。 動的リソース参照は、このようなリソースがアクセスされ、実行時にオブジェクト グラフにアクセスできるたびに新しい参照を強制します。 このアクセスを取得するために、DynamicResource 概念は、WPF プロパティ システムの依存関係プロパティと評価された式によってサポートされています。 したがって、依存関係プロパティターゲットに対してのみ DynamicResource を使用できます。 詳細については、「DynamicResource マークアップ拡張機能 を参照してください。

  • Binding は、実行時に親オブジェクトに適用されるデータ コンテキストを使用して、プロパティのデータ バインド値を提供します。 このマークアップ拡張は、データ バインディングを指定するための実質的なインライン構文を有効にするため、比較的複雑です。 詳細については、「バインディング マークアップ拡張」を参照してください。

  • RelativeSource は、実行時オブジェクト ツリー内で可能な複数のリレーションシップ間を移動できる Binding のソース情報を提供します。 これにより、マルチユース テンプレートで作成されるバインディングや、周囲のオブジェクト ツリーに関する完全な知識がなくてもコードで作成されるバインディングに特化したソーシングが提供されます。 詳細については、「RelativeSource MarkupExtension」を参照してください。

  • TemplateBinding を使用すると、コントロール テンプレートは、テンプレートを使用するクラスのオブジェクト モデル定義プロパティから取得されるテンプレート化されたプロパティの値を使用できます。 つまり、テンプレート定義内のプロパティは、テンプレートが適用された後にのみ存在するコンテキストにアクセスできます。 詳細については、「TemplateBinding Markup Extension」を参照してください。 TemplateBindingの実用的な使用方法の詳細については、「ControlTemplates サンプルを使用したスタイル設定」を参照してください。

  • ColorConvertedBitmap では、比較的高度なイメージング シナリオがサポートされています。 詳細については、ColorConvertedBitmap Markup Extensionを参照してください。

  • ComponentResourceKeyThemeDictionary では、特にカスタム コントロールと共にパッケージ化されたリソースとテーマに対して、リソース参照の側面がサポートされます。 詳細については、「ComponentResourceKey Markup ExtensionThemeDictionary Markup Extension、または Control Authoring Overviewを参照してください。

*拡張クラス

一般的な XAML 言語と WPF 固有のマークアップ拡張の両方について、各マークアップ拡張機能の動作は、MarkupExtensionから派生した *Extension クラスを介して XAML プロセッサに識別され、ProvideValue メソッドの実装を提供します。 各拡張機能のこのメソッドは、マークアップ拡張機能の評価時に返されるオブジェクトを提供します。 通常、返されるオブジェクトは、マークアップ拡張機能に渡されるさまざまな文字列トークンに基づいて評価されます。

たとえば、StaticResourceExtension クラスは、ProvideValue 実装が要求されたオブジェクトを返すように、実際のリソース参照の表面実装を提供します。その特定の実装の入力は、その x:Keyによってリソースを検索するために使用される文字列です。 既存のマークアップ拡張機能を使用している場合、この実装の詳細の多くは重要ではありません。

一部のマークアップ拡張では、文字列トークン引数が使用されません。 これは、静的または一貫性のある値を返すか、返される必要がある値のコンテキストが、serviceProvider パラメーターを介して渡されたサービスのいずれかを通じて使用できるためです。

*Extension 名前付けパターンは、利便性と一貫性を保つためです。 XAML プロセッサがそのクラスをマークアップ拡張のサポートとして識別するために必要ではありません。 コードベースに System.Xaml が含まれており、.NET Framework XAML サービスの実装を使用している限り、XAML マークアップ拡張機能として認識するために必要なのは、MarkupExtension から派生し、構築構文をサポートすることにあります。 WPF では、Bindingなど、*Extension の名前付けパターンに従わないマークアップ拡張機能を有効にするクラスを定義します。 通常、この理由は、純粋なマークアップ拡張のサポートを超えるシナリオがクラスでサポートされるためです。 Bindingの場合、そのクラスは XAML とは関係のないシナリオで、オブジェクトのメソッドとプロパティへの実行時アクセスをサポートします。

初期化テキストの拡張クラスの解釈

マークアップ拡張名に続き、中かっこ内の文字列トークンは、次のいずれかの方法で XAML プロセッサによって解釈されます。

  • コンマは、常に個々のトークンの区切り記号または区切り記号を表します。

  • 個々の区切られたトークンに等号が含まれていない場合、各トークンはコンストラクター引数として扱われます。 各コンストラクター パラメーターは、そのシグネチャで想定される型として、およびそのシグネチャで想定される適切な順序で指定する必要があります。

    手記

    XAML プロセッサは、ペアの数の引数数に一致するコンストラクターを呼び出す必要があります。 このため、カスタム マークアップ拡張機能を実装する場合は、同じ引数数を持つ複数のコンストラクターを指定しないでください。 同じパラメーター数を持つ複数のマークアップ拡張コンストラクター パスが存在する場合の XAML プロセッサの動作は定義されていませんが、この状況がマークアップ拡張型の定義に存在する場合は、XAML プロセッサが使用時に例外をスローすることが許可されることを予測する必要があります。

  • 個々の区切りトークンに等号が含まれている場合、XAML プロセッサは最初にマークアップ拡張機能のパラメーターなしのコンストラクターを呼び出します。 その後、各 name=value ペアは、マークアップ拡張機能に存在するプロパティ名と、そのプロパティに割り当てる値として解釈されます。

  • マークアップ拡張機能でコンストラクターの動作とプロパティ設定の動作の間に並列結果がある場合、使用する動作は関係ありません。 複数の設定可能なプロパティを持つマークアップ拡張では、プロパティ= ペアを使用するのが一般的です。これは、マークアップがより意図的になり、コンストラクターパラメーターを誤って入れ替えてしまう可能性が低くなるからです。 (property=value のペアを指定する場合、これらのプロパティは任意の順序で指定できます)。また、マークアップ拡張機能が、その設定可能なプロパティの 1 つ 1 つを設定するコンストラクター パラメーターを提供する保証はありません。 たとえば、Binding はマークアップ拡張であり、多くのプロパティは プロパティ= フォームの拡張機能を使用して設定できますが、Binding はパラメーターなしのコンストラクターと初期パスを設定するコンストラクターの 2 つのコンストラクターのみをサポートします。

  • リテラル コンマは、エスケープなしでマークアップ拡張機能に渡すことはできません。

エスケープ シーケンスとマークアップ拡張

XAML プロセッサでの属性処理では、マークアップ拡張シーケンスのインジケーターとして中かっこが使用されます。 必要に応じて、空の中かっこペアを使用してエスケープ シーケンスを入力し、リテラル中かっこの後にリテラル中かっこを入力することで、リテラル中かっこ文字属性値を生成することもできます。 「エスケープ シーケンスの {} - マークアップ拡張」を参照してください。

XAML でのマークアップ拡張機能のネスト

複数のマークアップ拡張機能の入れ子がサポートされており、各マークアップ拡張機能は最初に最も深く評価されます。 たとえば、次の使用方法を考えてみましょう。

<Setter Property="Background"  
  Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />  

この使用法では、x:Static ステートメントが最初に評価され、文字列が返されます。 その後、その文字列が DynamicResourceの引数として使用されます。

マークアップ拡張とプロパティ要素の構文

プロパティ要素の値を埋めるオブジェクト要素として使用する場合、マークアップ拡張クラスは、XAML で使用できる一般的な型指定されたオブジェクト要素と視覚的に区別できません。 一般的なオブジェクト要素とマークアップ拡張の実際の違いは、マークアップ拡張が型指定された値に評価されるか、式として遅延されるということです。 したがって、マークアップ拡張のプロパティ値の型エラーの可能性があるメカニズムは、他のプログラミング モデルでの遅延バインド プロパティの処理方法と同様に異なります。 通常のオブジェクト要素は、XAML の解析時に設定されているターゲット プロパティに対する型の一致について評価されます。

ほとんどのマークアップ拡張は、プロパティ要素を埋めるためにオブジェクト要素構文で使用される場合、コンテンツやその他のプロパティ要素構文を含んでいません。 したがって、オブジェクト要素タグを閉じ、子要素を指定しません。 XAML プロセッサによってオブジェクト要素が検出されるたびに、そのクラスのコンストラクターが呼び出され、解析された要素から作成されたオブジェクトがインスタンス化されます。 マークアップ拡張クラスは変わりありません。マークアップ拡張をオブジェクト要素構文で使用できるようにする場合は、パラメーターなしのコンストラクターを指定する必要があります。 一部の既存のマークアップ拡張には、有効な初期化のために指定する必要がある必須プロパティ値が少なくとも 1 つ含まれます。 その場合、通常、そのプロパティ値はオブジェクト要素のプロパティ属性として指定されます。 XAML 名前空間 (x:) 言語機能のWPF XAML 拡張機能 参照ページでは、必要なプロパティ (および必要なプロパティの名前) を持つマークアップ拡張機能が示されます。 参照ページでは、特定のマークアップ拡張に対してオブジェクト要素の構文または属性構文が許可されていない場合にも注意が必要です。 特に注目すべきケースは、x:Array Markup Extensionです。これは、その配列の内容をコンテンツとしてタグ付け内で指定する必要があるため、属性構文をサポートできません。 配列の内容は一般的なオブジェクトとして処理されるため、属性の既定の型コンバーターは使用できません。 また、x:Array Markup Extension には、 パラメーターが必要です。

関連項目