次の方法で共有


添付プロパティの概要

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

前提条件

この記事では、Windows Presentation Foundation (WPF) クラスの既存の依存関係プロパティのコンシューマーの観点から依存関係プロパティを理解し、依存関係プロパティの概要を読み取っていることを前提としています。 この記事の例に従うには、XAML について理解し、WPF アプリケーションを記述する方法も理解しておく必要があります。

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

添付プロパティの 1 つの目的は、親要素で定義されているプロパティに対して、異なる子要素が一意の値を指定できるようにすることです。 このシナリオの特定のアプリケーションでは、子要素がユーザー インターフェイス (UI) でどのように表示されるかを親要素に通知します。 1 つの例として、DockPanel.Dock プロパティがあります。 DockPanel.Dock プロパティは、DockPanel 自体ではなく、DockPanel 内に含まれる要素に設定するように設計されているため、添付プロパティとして作成されます。 DockPanel クラスは、DockPropertyという名前の静的 DependencyProperty フィールドを定義し、添付プロパティのパブリック アクセサーとして GetDock メソッドと SetDock メソッドを提供します。

XAML の添付プロパティ

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

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

<DockPanel>
    <TextBox DockPanel.Dock="Top">Enter text</TextBox>
</DockPanel>

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

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

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

Windows Presentation Foundation (WPF) では、WPF 型の UI 関連の添付プロパティのほとんどは依存関係プロパティとして実装されます。 添付プロパティは XAML の概念であり、依存関係プロパティは WPF の概念です。 WPF 添付プロパティは依存関係プロパティであるため、プロパティ メタデータなどの依存関係プロパティの概念と、そのプロパティ メタデータの既定値をサポートします。

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

添付プロパティは任意のオブジェクトで設定できますが、プロパティを設定すると具体的な結果が生成されたり、値が別のオブジェクトで使用されたりすることを自動的に意味するわけではありません。 一般に、添付プロパティは、さまざまな可能なクラス階層または論理リレーションシップから取得されたオブジェクトが、添付プロパティを定義する型に共通の情報を報告できるように意図されています。 添付プロパティを定義する型は、通常、次のいずれかのモデルに従います。

  • 添付プロパティを定義する型は、添付プロパティの値を設定する要素の親要素になるように設計されています。 その後、この型は、内部ロジックを介してオブジェクト ツリー構造に対して子オブジェクトを反復処理し、値を取得し、何らかの方法でそれらの値に作用します。

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

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

親定義の添付プロパティの例

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

DockPanelDockPanel.Dock 添付プロパティを定義し、DockPanel はレンダリング ロジックの一部としてクラス レベルのコードを持ちます (具体的には、MeasureOverrideArrangeOverride)。 DockPanel インスタンスは常に、その直接の子要素のいずれかが DockPanel.Dockの値を設定しているかどうかを確認します。 その場合、これらの値は、その特定の子要素に適用されるレンダリング ロジックの入力になります。 入れ子になった DockPanel インスタンスは、それぞれ独自の直接の子要素コレクションを処理しますが、その動作は、DockPanel が値 DockPanel.Dock 処理する方法に固有の実装です。 理論的には、直接の親以外の要素に影響を与える添付プロパティを持つことができます。 DockPanel.Dock 添付プロパティが、それに対して動作する DockPanel 親要素がない要素に設定されている場合、エラーや例外は発生しません。 これは、グローバル プロパティ値が設定されたが、情報を使用できる現在の DockPanel 親がないことを意味します。

コード の添付プロパティ

WPF の添付プロパティには、簡単に取得/設定アクセスするための一般的な CLR "ラッパー" メソッドがありません。 これは、添付プロパティが、プロパティが設定されているインスタンスの CLR 名前空間の一部であるとは限らないためです。 ただし、XAML プロセッサは、XAML の解析時にこれらの値を設定できる必要があります。 有効な添付プロパティの使用をサポートするには、添付プロパティの所有者の種類ごとに GetPropertyName および SetPropertyName の形式で専用のアクセサー メソッドを実装する必要があります。 これらの専用アクセサー メソッドは、コードで添付プロパティを取得または設定する場合にも役立ちます。 コードの観点から見ると、添付プロパティは、プロパティ アクセサーではなくメソッド アクセサーを持つバッキング フィールドに似ています。バッキング フィールドは、明示的に定義する必要はなく、任意のオブジェクトに存在できます。

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

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

XAML の場合と同様に、myCheckBox が 4 行目のコードによって myDockPanel の子要素としてまだ追加されていない場合、5 行目のコードでは例外は発生しませんが、プロパティ値は DockPanel の親と対話しないため、何もしません。 子要素に設定された DockPanel.Dock 値と DockPanel 親要素の存在のみが、レンダリングされたアプリケーションで有効な動作を引き起こします。 (この場合は、添付プロパティを設定してから、ツリーにアタッチできます。または、ツリーにアタッチし、添付プロパティを設定することもできます。どちらのアクションの順序でも同じ結果が得られます)。

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

プロパティを登録するときに、プロパティがレンダリングや測定などに影響するかどうかなど、プロパティの特性を指定する FrameworkPropertyMetadata が設定されます。 添付プロパティのメタデータは、通常、依存関係プロパティと同じになります。 添付プロパティ メタデータのオーバーライドで既定値を指定した場合、その値は、オーバーライドするクラスのインスタンスの暗黙的な添付プロパティの既定値になります。 特に、あるプロセスがそのプロパティの Get メソッドアクセサーを使用して添付プロパティの値を問い合わせる際に、メタデータを指定したクラスのインスタンスを指定し、その添付プロパティの値が設定されていない場合、既定値が報告されます。

プロパティでプロパティ値の継承を有効にする場合は、添付されていない依存関係プロパティではなく、添付プロパティを使用する必要があります。 詳細については、「プロパティ値の継承」を参照してください。

カスタム添付プロパティ

添付プロパティ を作成するタイミング

定義クラス以外のクラスでプロパティ設定メカニズムを使用できる理由がある場合は、添付プロパティを作成できます。 この最も一般的なシナリオはレイアウトです。 既存のレイアウト プロパティの例としては、DockPanel.DockPanel.ZIndexCanvas.Topがあります。 ここで有効なシナリオは、レイアウト制御要素に対する子要素として存在する要素が、レイアウトの親要素に対するレイアウト要件を個別に表すことができ、各要素は親が添付プロパティとして定義したプロパティ値を設定することです。

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

さらに別のシナリオとして、プロパティ ウィンドウ編集など、Visual Studio WPF デザイナーのサポートを受け取る方法もあります。 詳細については、「コントロールの作成の概要」を参照してください。

前述のように、プロパティ値の継承を使用する場合は、添付プロパティとして登録する必要があります。

添付プロパティ を作成する方法

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

DependencyProperty型の public static readonly フィールドを宣言して、添付プロパティを依存関係プロパティとして定義します。 このフィールドは、RegisterAttached メソッドの戻り値を使用して定義します。 フィールド名は、識別フィールドに名前を付ける確立された WPF パターンと、それらが表すプロパティに従うために、添付プロパティ名に文字列 Propertyを付加した名前と一致する必要があります。 添付プロパティプロバイダーは、添付プロパティのアクセサーとして静的な GetPropertyNameSetPropertyName メソッドを提供する必要があります。これを行わないと、プロパティシステムが添付プロパティを使用できなくなります。

手記

添付プロパティの get アクセサーを省略した場合、Visual Studio や Blend for Visual Studio などのデザイン ツールでは、プロパティのデータ バインディングは機能しません。

Get アクセサー

GetPropertyName アクセサーのシグネチャは、次のようにする必要があります。

public static object GetPropertyName(object target)

  • target オブジェクトは、実装でより具体的な型として指定できます。 たとえば、DockPanel.GetDock メソッドは、添付プロパティが UIElement インスタンスでのみ設定されることを意図しているため、パラメーターを UIElementとして型指定します。

  • 戻り値は、実装でより具体的な型として指定できます。 たとえば、GetDock メソッドは、値をその列挙型にのみ設定できるため、Dockとして型指定します。

Set アクセサー

SetPropertyName アクセサーのシグネチャは次の値である必要があります。

public static void SetPropertyName(object target, object value)

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

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

次の例は、依存関係プロパティの登録 (RegisterAttached メソッドを使用) と、GetPropertyName および SetPropertyName アクセサーを示しています。 この例では、添付プロパティ名は 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);
}
Public Shared ReadOnly IsBubbleSourceProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsBubbleSource", GetType(Boolean), GetType(AquariumObject), New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.AffectsRender))
Public Shared Sub SetIsBubbleSource(ByVal element As UIElement, ByVal value As Boolean)
    element.SetValue(IsBubbleSourceProperty, value)
End Sub
Public Shared Function GetIsBubbleSource(ByVal element As UIElement) As Boolean
    Return CType(element.GetValue(IsBubbleSourceProperty), Boolean)
End Function

添付プロパティ属性

WPF では、リフレクション プロセスや、リフレクションの一般的なユーザーやデザイナーなどのプロパティ情報に添付プロパティに関する情報を提供することを目的としたいくつかの .NET 属性が定義されています。 添付プロパティにはスコープが無制限の型があるため、デザイナーは、XAML を使用する特定のテクノロジ実装で定義されているすべての添付プロパティのグローバル リストを持つユーザーを圧倒しないようにする方法が必要です。 WPF が添付プロパティに対して定義する .NET 属性を使用して、特定の添付プロパティをプロパティ ウィンドウに表示する必要がある状況のスコープを設定できます。 独自のカスタム添付プロパティにもこれらの属性を適用することを検討してください。 .NET 属性の目的と構文は、適切なリファレンス ページで説明されています。

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

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

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

  • プロパティを添付プロパティとして、依存関係プロパティとして登録することもできますが、"ラッパー" 実装を公開することもできます。 この場合、プロパティは、その要素に対して、または XAML 添付プロパティ構文を使用して任意の要素に設定できます。 標準と添付の両方の使用に適したシナリオを持つプロパティの例は、FrameworkElement.FlowDirectionです。

関連項目