WPF のツリー

更新 : 2007 年 11 月

多くのテクノロジでは、要素およびコンポーネントはツリー構造で編成され、開発者はこのツリーを直接操作してアプリケーションのレンダリングに影響を与えます。Windows Presentation Foundation (WPF) でも各種のツリー構造というメタファを使用してプログラム要素間のリレーションシップを定義します。

このトピックには次のセクションが含まれています。

  • WPF のツリー
  • 論理ツリー
  • ビジュアル ツリー
  • ツリー、コンテンツ要素、およびコンテンツ ホスト
  • ツリーの移動
  • "ツリー" としてのルーティング イベントのルート
  • リソースとツリー
  • 関連トピック

WPF のツリー

WPF の基本のツリー構造は、要素ツリーと呼ばれます。XAML でアプリケーション ページを作成した場合、ツリー構造は、マークアップ内の要素の入れ子のリレーションシップに基づいて作成されます。コードでアプリケーションを作成した場合、ツリー構造は、指定した要素のコンテンツ モデルを実装するプロパティにプロパティ値を割り当てる方法に基づいて作成されます。Windows Presentation Foundation (WPF) では、実際には、論理ツリーとビジュアル ツリーという 2 つの方法で、要素ツリーを処理および概念化しています。論理ツリーとビジュアル ツリーの違いが必ずしも重要とは限りませんが、特定の WPF サブシステムでは問題が生じることがあり、マークアップやコード内での選択に影響することがあります。

論理ツリーやビジュアル ツリーを直接操作するとは限らない場合でも、ツリーの操作方法の概念を理解することは、WPF でのプロパティの継承やイベントのルーティングを理解するうえで役立ちます。

論理ツリー

WPF では、プロパティを使用して要素にコンテンツを追加します。たとえば、Items プロパティを使用して、ListBox コントロールに項目を追加します。これにより、ListBox コントロールの ItemCollection コレクションに項目を配置しています。DockPanel に要素を追加するには、Children プロパティを使用します。この場合は、DockPanelUIElementCollection に要素を追加しています。コード例については、「方法 : 要素を動的に追加する」を参照してください。

Extensible Application Markup Language (XAML) では、次の例に示すように、ListBox にリスト項目を配置する場合、あるいは DockPanel にコントロールまたは他の要素を配置する場合は、Items プロパティと Children プロパティも明示的または暗黙的に使用します。

<DockPanel
  Name="ParentElement"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >

  <!--implicit: <DockPanel.Children>-->
  <ListBox DockPanel.Dock="Top">
    <!--implicit: <ListBox.Items>-->
    <ListItem>
      <Paragraph>Dog</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>Cat</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>Fish</Paragraph>
    </ListItem>
    <!--implicit: </ListBox.Items>-->
  </ListBox>
  <Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>

  <!--implicit: </DockPanel.Children>-->
</DockPanel>

XAML リーダーが、アプリケーションのランタイム オブジェクト表現の実行可能ファイルを作成するオブジェクトの作成時にプロパティ要素を推測することから、プロパティ要素タグは明示的に必要ではないことに注意してください。作成される論理ツリーおよび暗黙的なタグに XAML 構文が対応付けられる方法の詳細については、「XAML 構文用語」または「XAML の概要」を参照してください。次の図は、実行時に構築される論理ツリーの概念図を示しています (ここではボタンの分岐が省略されています)。

ジェネリックな論理ツリーの概念図
ツリー ダイアグラム

論理ツリーの目的

論理ツリーは、コンテンツ モデルが、使用可能な子要素を簡単に反復処理できること、およびコンテンツ モデルの拡張を目的としています。論理ツリーは、論理ツリー内のすべての要素がいつ読み込まれるかなど、特定の通知のフレームワークも提供します。

また、リソース参照は、最初は要求元の要素、次は親要素で、Resources コレクションの論理ツリーを介した上方への検索によって解決されます。論理ツリーとビジュアル ツリーの両方が存在する場合は、論理ツリーがリソースの検索に使用されます。リソースの詳細については、「リソースの概要」を参照してください。

論理ツリーのオーバーライド

高度なコントロールを作成するときには、一般的なオブジェクトまたはコンテンツ モデルによって論理ツリー内の要素を追加または削除する方法を定義しているいくつかの API をオーバーライドして、論理ツリーをオーバーライドすることができます。論理ツリーのオーバーライド例については、「方法: 論理ツリーをオーバーライドする」を参照してください。

プロパティ値の継承

プロパティ値の継承は、ハイブリッド ツリーを通じて行われます。プロパティの継承を有効化する Inherits プロパティが含まれる実際のメタデータは、WPF フレームワーク レベルの FrameworkPropertyMetadata クラスです。このため、元の値を保持する親と継承する子の両方が FrameworkElement または FrameworkContentElement であり、両方が、ある論理ツリーに含まれている必要があります。ただし、プロパティ値の継承は、論理ツリーにない、介在するビジュアル要素を通じて存続できるため、親と子の論理ツリーが離れていてもかまいません。プロパティ値の継承が、このような境界を越えて変わらず動作するためには、継承するプロパティを添付プロパティとして登録する必要があります。プロパティの継承で使用する正確なツリーを、実行時であっても、ヘルパー クラス ユーティリティ メソッドで完全に予測することができません。詳細については、「プロパティ値の継承」を参照してください。

ビジュアル ツリー

WPF では、論理ツリーの概念に加えて、ビジュアル ツリーの概念も存在します。ビジュアル ツリーは、Visual 基本クラスによって表されるビジュアルの構造を示します。コントロールのテンプレートを作成する場合は、そのコントロールに適用するビジュアル ツリーを定義または再定義します。ビジュアル ツリーは、パフォーマンスの向上および最適化のために、描画に対して低レベルの制御が必要な開発者にとっても非常に有用です。従来の WPF アプリケーションのプログラミングの一環としてビジュアル ツリーについて公開されていることの 1 つは、ルーティング イベントのイベント ルートは、通常、論理ツリーではなくビジュアル ツリーをたどるということです。ルーティング イベントの動作の細部は、コントロールの作成者でない限り、すぐにはわからない場合があります。ビジュアル ツリーを介したルーティングにより、ビジュアルのレベルで構成を実装するコントロールによってイベントを処理したり、イベント setter を作成したりできるようになります。

ツリー、コンテンツ要素、およびコンテンツ ホスト

コンテンツ要素 (ContentElement から派生するクラス) はビジュアル ツリーには含まれません。これらは Visual を継承しておらず、視覚的表現を持ちません。UI で表示させるには、Visual および論理ツリー要素であり、通常は FrameworkElement であるコンテンツ ホスト内で、ContentElement をホストする必要があります。コンテンツ ホストは、コンテンツにとって "ブラウザ" のようなものであり、ホストが制御する画面領域内でそのコンテンツの表示方法を選択するものと考えることができます。コンテンツがホストされると、このコンテンツは、ビジュアル ツリーに通常関連付けられている特定のツリー プロセスで 1 つの要因になることができます。一般に、FrameworkElement ホスト クラスには、ホストされるコンテンツが実際にはビジュアル ツリーに含まれない場合でも、コンテンツの論理ツリーのサブノードを介して、ホストされる ContentElement をイベント ルートに追加する実装コードが含まれます。これは、ContentElement が、自身以外の要素にルーティングするルーティング イベントを調達できるようにするために必要です。

ツリーの移動

LogicalTreeHelper クラスは、論理ツリーの移動用に GetChildrenGetParent、および FindLogicalNode の各メソッドを提供します。これらのコントロールはほとんど常に論理上の子要素を専用のコレクション プロパティとして公開し、Add、インデクサなどのコレクション API をサポートしているため、多くの場合、既存のコントロールの論理ツリーを移動する必要はありません。ツリーの移動が使用される主なシナリオは、コントロール作成者が、コレクション プロパティが定義済みの ItemsControlPanel など、対象とするコントロール パターンから派生することを選択しない場合や、コレクション プロパティを独自にサポートする場合です。

また、ビジュアル ツリーはビジュアル ツリーの移動で VisualTreeHelper などのヘルパー クラスをサポートします。ビジュアル ツリーでは、コントロール固有のプロパティを使用した便利な移動方法は公開されていないため、プログラミング シナリオで必要な場合には、ビジュアル ツリーを移動する方法として VisualTreeHelper クラスが推奨されます。詳細については、「Windows Presentation Foundation のグラフィックス レンダリングの概要」を参照してください。

"ツリー" としてのルーティング イベントのルート

前述のように、ルーティング イベントのルートは効率的にツリーをたどり、トンネル ルーティング イベントかバブル ルーティング イベントかに応じて、ツリーを上方向または下方向へ移動します。イベント ルートの概念では、実際にルーティングするイベントの発生とは無関係にイベント ルートを "移動する" のに使用される、ヘルパー クラスを直接にはサポートしていません。ルートを表す EventRoute クラスはありますが、そのクラスのメソッドは、通常、内部でのみ使用されています。

リソースとツリー

リソース検索では、基本的に論理ツリーを走査します。論理ツリーにないオブジェクトはリソースを参照できますが、検索は、そのオブジェクトが論理ツリーに接続している場所から開始します。論理ツリー ノードのみが ResourceDictionary を含む Resources プロパティを使用できるため、リソースの検索時にビジュアル ツリーを走査しても利点はありません。

ただし、リソース検索も、直接の論理ツリーを超えて拡張できます。アプリケーション マークアップの場合、アプリケーション リソース、テーマ サポート、およびシステム値へとリソース検索が続きます。リソース参照が動的な場合は、テーマ自体も、テーマ論理ツリーの外部にあるシステム値を参照できます。リソースおよび検索ロジックの詳細については、「リソースの概要」を参照してください。

参照

概念

入力の概要

Windows Presentation Foundation のグラフィックス レンダリングの概要

ルーティング イベントの概要

要素ツリーに存在しないオブジェクト要素の初期化

WPF アーキテクチャ