次の方法で共有


WPF XAML 名前スコープ

XAML 名前スコープは、XAML で定義されているオブジェクトを識別する概念です。 XAML 名前スコープ内の名前を使用して、オブジェクトの XAML 定義名とそのオブジェクト ツリー内の同等のインスタンスの間のリレーションシップを確立できます。 通常、WPF マネージ コードの XAML 名前スコープは、XAML アプリケーションの個々の XAML ページ ルートを読み込むときに作成されます。 プログラミング オブジェクトとしての XAML 名前スコープは、 INameScope インターフェイスによって定義され、実用的なクラス NameScopeによっても実装されます。

読み込まれた XAML アプリケーションの名前スコープ

より広範なプログラミングまたはコンピューター サイエンスのコンテキストでは、多くの場合、プログラミングの概念には、オブジェクトへのアクセスに使用できる一意の識別子または名前の原則が含まれます。 識別子または名前を使用するシステムの場合、名前スコープは、その名前のオブジェクトが要求された場合にプロセスまたは手法が検索する境界、または識別名の一意性が適用される境界を定義します。 これらの一般的な原則は、XAML 名前スコープに当てはまります。 WPF では、XAML 名前スコープは、ページが読み込まれるときに XAML ページのルート要素に作成されます。 ページ ルートから始まる XAML ページ内で指定された各名前は、関連する XAML 名前スコープに追加されます。

WPF XAML では、共通のルート要素 ( PageWindowなど) である要素は常に XAML 名前スコープを制御します。 FrameworkElementFrameworkContentElementなどの要素がマークアップ内のページのルート要素である場合、XAML プロセッサは、Pageが動作する XAML 名前スコープを提供できるように、Page ルートを暗黙的に追加します。

WPF ビルド アクションは、XAML マークアップ内の要素に Name または x:Name 属性が定義されていない場合でも、XAML 運用環境用の XAML 名前スコープを作成します。

XAML 名前スコープで同じ名前を 2 回使用しようとすると、例外が発生します。 分離コードを持ち、コンパイル済みアプリケーションの一部である WPF XAML の場合、最初のマークアップ コンパイル中にページの生成されたクラスを作成するときに、WPF ビルド アクションによってビルド時に例外が発生します。 ビルド アクションによってマークアップ コンパイルされない XAML の場合、XAML の読み込み時に XAML 名前スコープの問題に関連する例外が発生する可能性があります。 XAML デザイナーでは、デザイン時に XAML 名前スコープの問題が予想される場合もあります。

ランタイム オブジェクト ツリーへのオブジェクトの追加

XAML が解析される瞬間は、WPF XAML 名前スコープが作成および定義された時点を表します。 そのツリーを生成した XAML が解析された後の特定の時点でオブジェクト ツリーにオブジェクトを追加した場合、新しいオブジェクトの Name または x:Name 値は、XAML 名前スコープ内の情報を自動的に更新しません。 XAML の読み込み後にオブジェクトの名前を WPF XAML 名前スコープに追加するには、XAML 名前スコープ (通常は XAML ページ ルート) を定義するオブジェクトに対して、 RegisterName の適切な実装を呼び出す必要があります。 名前が登録されていない場合、追加されたオブジェクトは、 FindNameなどのメソッドを介して名前で参照することはできません。また、その名前をアニメーションのターゲット設定に使用することはできません。

アプリケーション開発者にとって最も一般的なシナリオは、 RegisterName を使用して、ページの現在のルートにある XAML 名前スコープに名前を登録することです。 RegisterName は、アニメーションのオブジェクトを対象とするストーリーボードの重要なシナリオの一部です。 詳細については、「 ストーリーボードの概要」を参照してください。

XAML 名前スコープを定義するオブジェクト以外のオブジェクトに対して RegisterName を呼び出した場合でも、呼び出し元のオブジェクトが保持されている XAML 名前スコープに名前が登録されます。これは、XAML 名前スコープ定義オブジェクトで RegisterName を呼び出した場合と同様です。

コード内の XAML 名前スコープ

コードで XAML 名前スコープを作成して使用できます。 XAML 名スコープの作成に関連する API と概念は、純粋なコードを使用する場合でも同じです。WPF の XAML プロセッサでは、XAML 自体を処理するときにこれらの API と概念が使用されるためです。 概念と API は主に、XAML で部分的または完全に定義されるオブジェクト ツリー内の名前でオブジェクトを検索できるようにするために存在します。

読み込まれた XAML からではなくプログラムで作成されるアプリケーションの場合、XAML 名前スコープを定義するオブジェクトは、インスタンスでの XAML 名前スコープの作成をサポートするために、 INameScopeを実装するか、 FrameworkElement または派生クラス FrameworkContentElement する必要があります。

また、XAML プロセッサによって読み込まれ、処理されない要素の場合、オブジェクトの XAML 名前スコープは既定では作成または初期化されません。 後で名前を登録するすべてのオブジェクトに対して、新しい XAML 名前スコープを明示的に作成する必要があります。 XAML 名前スコープを作成するには、静的な SetNameScope メソッドを呼び出します。 それを所有するオブジェクトを dependencyObject パラメーターとして指定し、新しい NameScope コンストラクターを value パラメーターとして呼び出します。

dependencyObjectSetNameScopeとして指定されたオブジェクトがINameScope実装(FrameworkElementまたはFrameworkContentElement)でない場合、子要素に対してRegisterNameを呼び出しても効果はありません。 新しい XAML 名前スコープを明示的に作成できない場合、 RegisterName を呼び出すと例外が発生します。

コードで XAML 名前スコープ API を使用する例については、「 名前スコープの定義」を参照してください。

スタイルとテンプレートにおける XAML 名前スコープ

WPF のスタイルとテンプレートでは、簡単な方法でコンテンツを再利用および再適用できます。 ただし、スタイルとテンプレートには、テンプレート レベルで定義された XAML 名を持つ要素も含まれる場合があります。 同じテンプレートが 1 つのページで複数回使用される場合があります。 このため、スタイルとテンプレートはどちらも、スタイルまたはテンプレートが適用されるオブジェクト ツリー内の任意の場所に関係なく、独自の XAML 名前スコープを定義します。

次の例を確認してください。

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Page.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
      <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
        <ContentPresenter/>
      </Border>      
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
    <Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
  </StackPanel>
</Page>

ここでは、同じテンプレートが 2 つの異なるボタンに適用されます。 テンプレートに個別の XAML 名前スコープがない場合、テンプレートで使用される TheBorder 名が XAML 名前スコープで名前の競合を引き起こします。 テンプレートの各インスタンス化には独自の XAML 名前スコープがあるため、この例では、インスタンス化された各テンプレートの XAML 名前スコープには正確に 1 つの名前が含まれます。

スタイルは独自の XAML 名前スコープも定義します。ほとんどの場合、ストーリーボードの一部に特定の名前を割り当てることができます。 これらの名前を使用すると、テンプレートがコントロールのカスタマイズの一部として再定義された場合でも、その名前の要素を対象とするコントロール固有の動作が可能になります。

XAML 名前スコープが異なるため、テンプレート内の名前付き要素の検索は、ページ内でテンプレート化されていない名前付き要素を見つけるよりも困難です。 まず、テンプレートが適用されているコントロールの Template プロパティ値を取得して、適用されたテンプレートを決定する必要があります。 次に、テンプレートバージョンの FindNameを呼び出し、テンプレートが適用されたコントロールを 2 番目のパラメーターとして渡します。

コントロール作成者で、適用されたテンプレート内の特定の名前付き要素がコントロール自体によって定義された動作のターゲットである規則を生成する場合は、コントロール実装コードから GetTemplateChild メソッドを使用できます。 GetTemplateChild メソッドは保護されているため、コントロール作成者のみがアクセスできます。

テンプレート内から作業していて、テンプレートが適用されている XAML 名前スコープにアクセスする必要がある場合は、 TemplatedParentの値を取得し、そこで FindName 呼び出します。 テンプレート内で作業する例として、適用されたテンプレート内の要素からイベントが発生するイベント ハンドラーの実装を記述する場合があります。

FrameworkElement には、 FindNameRegisterName 、および UnregisterName メソッドがあります。 これらのメソッドを呼び出すオブジェクトが XAML 名前スコープを所有している場合、メソッドは関連する XAML 名前スコープのメソッドを呼び出します。 それ以外の場合は、親要素が XAML 名前スコープを所有しているかどうかを確認します。このプロセスは、XAML 名前スコープが見つかるまで再帰的に続行されます (XAML プロセッサの動作により、ルートに XAML 名前スコープがあることが保証されます)。 FrameworkContentElement には類似した動作があります。ただし、XAML 名前スコープを所有する FrameworkContentElement はありません。 メソッドは FrameworkContentElement に存在するため、呼び出しを最終的に FrameworkElement 親要素に転送できます。

SetNameScope は、新しい XAML 名前スコープを既存のオブジェクトにマップするために使用されます。 XAML 名前スコープをリセットまたはクリアするために SetNameScope を複数回呼び出すことができますが、これは一般的な使用方法ではありません。 また、 GetNameScope は通常、コードから使用されません。

XAML 名前スコープの実装

次のクラスは、 INameScope を直接実装します。

ResourceDictionary は XAML 名または名前スコープを使用しません。これはディクショナリの実装であるため、代わりにキーを使用します。 ResourceDictionaryINameScopeを実装する唯一の理由は、ユーザー コードに例外を発生させ、真の XAML 名前スコープとResourceDictionaryがキーを処理する方法の区別を明確にし、XAML 名前スコープが親要素によってResourceDictionaryに適用されないようにするためです。

FrameworkTemplateおよびStyleは、明示的なインターフェイス定義を使用してINameScopeを実装します。 明示的な実装により、これらの XAML 名前スコープは、 インターフェイスを介してアクセスするときに従来どおりに動作します。これは、XAML 名前スコープが WPF 内部プロセスによって通信される方法です。 ただし、明示的なインターフェイス定義は、FrameworkTemplateStyleの従来の API サーフェスの一部ではありません。これは、INameScopeFrameworkTemplateStyle メソッドを直接呼び出す必要があまりなく、代わりに GetTemplateChild などの他の API を使用するためです。

次のクラスは、 System.Windows.NameScope ヘルパー クラスを使用し、 NameScope.NameScope 添付プロパティを介してその XAML 名前スコープの実装に接続することによって、独自の XAML 名前スコープを定義します。

こちらも参照ください