添付プロパティの概要

添付プロパティとは、Extensible Application Markup Language (XAML) によって定義される概念です。添付プロパティの目的は、任意のオブジェクトに対して設定可能な一種のグローバル プロパティとして使用することです。Windows Presentation Foundation (WPF) では一般に、添付プロパティは、従来のプロパティ "ラッパー" を持たない特殊な形式の依存関係プロパティとして定義されます。

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

  • 必要条件
  • 添付プロパティを使用する理由
  • XAML での添付プロパティ
  • 所有する型が添付プロパティを使用する方法
  • コードでの添付プロパティ
  • 添付プロパティのメタデータ
  • いつ添付プロパティを作成するか
  • 添付プロパティの作成方法
  • 添付プロパティの詳細情報
  • 関連トピック

必要条件

このトピックでは、Windows Presentation Foundation (WPF) のクラスに対する既存の依存関係プロパティを使用するコンシューマの観点から 依存関係プロパティを理解し、「依存関係プロパティの概要」を通読していることを前提としています。このトピックの例を実行するには、Extensible Application Markup Language (XAML) について理解し、WPF アプリケーションの記述に精通している必要があります。

添付プロパティを使用する理由

添付プロパティの目的の 1 つは、実際には親要素で定義されるプロパティについて、子要素がそれぞれ別の値を指定できるようにすることです。このシナリオは、たとえば、子要素をユーザー インターフェイス (UI) にどのように表示するかを子要素から親要素に通知させるという状況に応用されます。System.Windows.Controls.DockPanel.Dock プロパティがその一例です。System.Windows.Controls.DockPanel.Dock プロパティが添付プロパティとして作成されるのは、このプロパティが DockPanel 自体ではなく DockPanel に含まれる要素に対して設定するように設計されているからです。DockPanel クラスでは、DockProperty という名前の静的 DependencyProperty フィールドが定義されており、添付プロパティのパブリック アクセサとして GetDock メソッドと SetDock メソッドが定義されています。

XAML での添付プロパティ

XAML では、AttachedPropertyProvider.PropertyName 構文を使用して添付プロパティを設定します。

XAML で System.Windows.Controls.DockPanel.Dock を設定する方法を次の例に示します。

<DockPanel>
  <CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>

使用方法が静的プロパティに少し似ていることに注意してください。名前で指定されたインスタンスを参照するのではなく、添付プロパティを所有および登録する DockPanel 型を常に参照します。

また、XAML では、添付プロパティはマークアップ内で設定する属性であるので、有効な操作は設定のみです。XAML の中でプロパティを直接取得することはできませんが、スタイルのトリガなど、間接的に値を比較する機構があります (詳細については、「スタイルとテンプレート」を参照してください)。

WPF での添付プロパティの実装

Windows Presentation Foundation (WPF) において、WPF の型に対して存在する添付プロパティのほとんどは、依存関係プロパティとして実装されます。添付プロパティは XAML の概念であり、依存関係プロパティは WPF の概念です。WPF の添付プロパティは依存関係プロパティであるので、依存関係プロパティの概念のうち、メタデータなど一部はサポートされますが、その他の概念はサポートされません。たとえば、添付プロパティが値を継承することはできません。

所有する型が添付プロパティを使用する方法

添付プロパティはどのオブジェクトに対しても設定可能ですが、プロパティを設定することで有形の結果が得られたり、その値が読み取られたりするわけではありません。大まかにいって、添付プロパティの目的は、さまざまなクラス階層または論理上のリレーションシップから発生するオブジェクトのそれぞれが、所有する型に対して共通の情報を報告できるようにすることです。添付プロパティを定義する型は一般に、次のいずれかのモデルに従います。

  • 添付プロパティを定義する型は、添付プロパティの値を設定する要素の親要素になることができるように設計されています。この型は、内部ロジックを通じて自身の子要素を反復処理して値を取得し、その値に対するなんらかの処理を行います。

  • 添付プロパティを定義する型は、さまざまな親要素およびコンテンツ モデルの子要素として使用されます。

  • 添付プロパティを定義する型は、サービスを表します。その他の型は、添付プロパティの値を設定します。プロパティを設定する要素がサービスのコンテキスト内で評価されるときに、サービス クラスの内部ロジックを通じて添付プロパティの値が取得されます。

添付プロパティが定義された親要素の例

WPF が添付プロパティを定義する最も一般的なシナリオは、親要素が子要素のコレクションをサポートすると同時に、親要素が実装した動作の詳細を子要素ごとに別個に報告させるというものです。

DockPanel では System.Windows.Controls.DockPanel.Dock 添付プロパティが定義され、DockPanel のレンダリング ロジックの一部としてクラス レベルのコードが設定されています (具体的には MeasureOverrideArrangeOverride)。DockPanel のインスタンスは、直接の子要素が の値を設定しているかどうかを常に確認します。設定されている場合は、その値を入力とするレンダリング ロジックを、その子要素に適用します。入れ子になった DockPanel インスタンスは、それぞれ自身の直接の子要素のコレクションを扱いますが、その動作は実装によって異なります。入れ子になっている場合でも添付プロパティがすべての親要素によって処理されるようにすることや、直接の子要素のコレクション内にない子要素を扱うことも、理論的には可能です。System.Windows.Controls.DockPanel 添付プロパティが設定されている要素が、作用対象の DockPanel 親要素を持たない場合も、エラーや例外は発生しません。これは、グローバル プロパティ値が設定されたけれども、その情報を利用できる親 DockPanel が現在存在しないことを意味します。

コードでの添付プロパティ

WPF の添付プロパティには、get および set のアクセスを容易にするための標準的な CLR "ラッパー" メソッドはありません。これは、添付プロパティが設定されたインスタンスの CLR 名前空間に、その添付プロパティが属しているとは限らないからです。ただし、XAML リーダーは、XAML の処理時にこれらの値を設定できます。添付プロパティを有効にするには、添付プロパティの所有者型が Get[PropertyName] および Set[PropertyName] の形式で専用アクセサ メソッドを実装する必要があります。コードで添付プロパティを取得または設定するときも、この専用アクセサ メソッドを使用する必要があります。

コードで添付プロパティを設定する方法を次の例に示します。この例の myCheckBox は、CheckBox クラスのインスタンスです。

DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);

XAML の場合と同様に、コードの 3 行目の時点で myCheckBoxmyDockPanel の子要素として追加されていなくても、コードの 4 行目で例外が発生することはありませんが、プロパティ値と親 DockPanel とが相互作用しないので、何も実行されません。子要素で System.Windows.Controls.DockPanel.Dock 値が設定されていて、親要素の DockPanel が存在する場合にのみ、レンダリングされたアプリケーション内で有効な動作が実行されます。

添付プロパティのメタデータ

プロパティを登録するときに、FrameworkPropertyMetadata を設定してプロパティの特性を指定します。たとえば、プロパティがレンダリングやサイズ測定に影響を及ぼすかどうかを指定します。添付プロパティのメタデータは基本的に、依存関係プロパティのメタデータと同様ですが、添付プロパティではプロパティの継承がサポートされないという例外があります。

いつ添付プロパティを作成するか

添付プロパティを作成するのは、プロパティを定義するクラス以外のクラスでプロパティを設定するための機構が必要な場合です。この最も一般的なシナリオはレイアウトです。既存のレイアウト プロパティの例としては、System.Windows.Controls.DockPanel.DockSystem.Windows.Controls.Panel.ZIndexSystem.Windows.Controls.Canvas.Top などがあります。これによって実現するシナリオは、レイアウト制御要素の子要素として存在する要素が、レイアウト親要素に対して個別にレイアウト要件を表現するというものです。親が添付プロパティとして定義したプロパティ値を、個々の子要素が設定します。

添付プロパティを使用するシナリオには、この他に、クラスによってサービスを表す場合に、クラスとサービスとをより透過的に統合できるようにするというものがあります。

添付プロパティの作成方法

クラスで定義する添付プロパティが、他の型での使用のみを目的としている場合は、このクラスが DependencyObject から派生していなくてもかまいません。しかし、添付プロパティが依存関係プロパティでもあるという全体的な WPF モデルに従う場合は、DependencyObject から派生している必要があります。

添付プロパティを依存関係プロパティとして定義するには、DependencyProperty 型のパブリックな静的フィールドを宣言します。このフィールドを定義するには、RegisterAttached メソッドの戻り値を使用します。フィールド名は、添付プロパティと同じ名前に文字列 Property を付加したものである必要があります。識別するフィールドとそのフィールドが表すプロパティに関する、WPF で確立された命名パターンに従うためです。また、添付プロパティのプロバイダは、添付プロパティのアクセサとして Get[PropertyName] および Set[PropertyName] の静的メソッドを持つ必要があります。これらのメソッドがないプロパティ システムは、添付プロパティを使用することができません。

Get アクセサ

Get[PropertyName] アクセサの署名の形式は次のとおりです。

public static object Get PropertyName (object target )

  • target オブジェクトは、実装内で具体的な型として指定できます。たとえば、System.Windows.Controls.DockPanel.GetDock(System.Windows.UIElement) メソッドでは、このパラメータの型が UIElement となっています。これは、添付プロパティが UIElement インスタンスに対してのみ設定されることになっているからです。

  • 戻り値は、実装内で具体的な型として指定できます。たとえば、GetDock メソッドの戻り値の型は Dock ですが、この値はその列挙体にのみ設定可能だからです。

Set アクセサ

Set[PropertyName] アクセサの署名の形式は次のとおりです。

public static void Set PropertyName (object target , object value )

  • target オブジェクトは、実装の中で具体的な型として指定できます。たとえば、SetDock メソッドのこのオブジェクトの型は UIElement となっています。これは、添付プロパティが UIElement インスタンスに対してのみ設定されることになっているからです。

  • value オブジェクトは、実装の中で具体的な型として指定できます。たとえば、SetDock メソッドのこのパラメータの型は Dock となっています。この値は、その列挙体にのみ設定可能だからです。このメソッドの値は、マークアップ内での添付プロパティの使用が XAML ローダーによって検出されたときのローダーからの入力値であることに注意してください。この入力は、マークアップ内では XAML の属性値として指定される値です。したがって、属性値 (最終的には文字列) から適切な型を作成するには、使用する型でサポートされる型変換、値のシリアライザ、またはマークアップ拡張機能が必要です。

依存関係プロパティの登録 (RegisterAttached メソッドを使用) と、Get[PropertyName] アクセサおよび Set[PropertyName] アクセサの例を次に示します。この例では、添付プロパティ名は IsBubbleSource です。したがって、アクセサの名前は GetIsBubbleSource および SetIsBubbleSource となります。

public static readonly DependencyProperty IsBubbleSourceProperty = DependencyProperty.RegisterAttached(
  "IsBubbleSource",
  typeof(Boolean),
  typeof(AquariumObject),
  new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
  element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
  return (Boolean)element.GetValue(IsBubbleSourceProperty);
}

添付プロパティの詳細情報

  • 添付プロパティの作成の詳細については、「方法 : 添付プロパティを登録する」を参照してください。

  • 依存関係プロパティと添付プロパティの使用方法のより高度なシナリオについては、「カスタム依存関係プロパティ」を参照してください。

  • プロパティを添付プロパティおよび依存関係プロパティとして登録するけれども "ラッパー" 実装も公開するということも可能です。この場合、プロパティはその要素に対して設定することも、XAML 添付プロパティ構文を通して任意の要素に対して設定することもできます。

参照

関連項目

DependencyProperty

概念

依存関係プロパティの概要
カスタム依存関係プロパティ