次の方法で共有


添付プロパティの概要

添付プロパティは、拡張アプリケーション マークアップ言語 (XAML) の概念です。 添付プロパティを使用すると、 DependencyObjectから派生するすべての XAML 要素に対して追加のプロパティと値のペアを設定できます。ただし、その要素では、そのオブジェクト モデルで追加のプロパティが定義されていません。 追加のプロパティには、グローバルにアクセスできます。 添付プロパティは、通常、従来のプロパティ ラッパーを持たない特殊な形式の依存関係プロパティとして定義されます。

[前提条件]

この記事では、依存関係プロパティの基本的な知識と、依存関係プロパティの概要読んだことを前提としています。 この記事の例に従うには、XAML に慣れている場合や、Windows Presentation Foundation (WPF) アプリケーションを記述する方法を理解している場合に役立ちます。

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

添付プロパティを使用すると、子要素は、親要素で定義されているプロパティの一意の値を指定できます。 一般的なシナリオは、親要素による UI でのレンダリング方法を指定する子要素です。 たとえば、DockPanel.Dockは、DockPanel自体ではなく、DockPanelの子要素に設定されるため、添付プロパティです。 DockPanel クラスは、DependencyPropertyという名前の静的DockProperty フィールドを定義し、添付プロパティのパブリック アクセサーとしてGetDockメソッドとSetDock メソッドを提供します。

XAML の添付プロパティ

XAML では、構文 <attached property provider type>.<property name>を使用して添付プロパティを設定します。添付プロパティ プロバイダーは、添付プロパティを定義するクラスです。 次の例は、 DockPanel の子要素で DockPanel.Dock プロパティ値を設定する方法を示しています。

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

使用法は、インスタンス名ではなく、添付プロパティ (たとえば、 DockPanel) を所有し、登録する型を参照するという点で静的プロパティに似ています。

XAML 属性を使用して添付プロパティを指定する場合は、set アクションのみが適用されます。 XAML を使用してプロパティ値を直接取得することはできませんが、 スタイルのトリガーなど、値を比較するための間接的なメカニズムがいくつかあります。

WPF の添付プロパティ

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

添付プロパティの使用モデル

どのオブジェクトでも添付プロパティ値を設定できますが、値を設定すると具体的な結果が生成されたり、値が別のオブジェクトによって使用されたりするわけではありません。 添付プロパティの主な目的は、さまざまなクラス階層と論理リレーションシップのオブジェクトが、添付プロパティを定義する型に共通の情報を報告する方法を提供することです。 添付プロパティの使用法は、通常、次のいずれかのモデルに従います。

  • 添付プロパティを定義する型は、添付プロパティの値を設定する要素の親です。 親型は、オブジェクト ツリー構造に対して動作し、値を取得し、何らかの方法でそれらの値に対して動作する内部ロジックを介して子オブジェクトを反復処理します。
  • 添付プロパティを定義する型は、さまざまな可能な親要素およびコンテンツ モデルの子要素として使用されます。
  • 添付プロパティを定義する型は、サービスを表します。 その他の型は、添付プロパティの値を設定します。 次に、プロパティを設定する要素がサービスのコンテキストで評価されると、添付プロパティの値はサービス クラスの内部ロジックを通じて取得されます。

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

WPF が添付プロパティを定義する一般的なシナリオは、親要素が子要素コレクションをサポートし、親要素が各子要素によって報告されたデータに基づく動作を実装する場合です。

DockPanel は、 DockPanel.Dock 添付プロパティを定義します。 DockPanel には、クラス レベルのコード (特に MeasureOverrideArrangeOverride) があります。これは、そのレンダリング ロジックの一部です。 DockPanelインスタンスは、その直接の子要素のいずれかがDockPanel.Dockの値を設定しているかどうかを確認します。 その場合、これらの値は、各子要素に適用されるレンダリング ロジックへの入力になります。 添付プロパティが直接の親を超えて要素に影響を与えることは理論的には可能ですが、入れ子になった DockPanel インスタンスの定義された動作は、その直接の子要素コレクションとのみ対話することです。 したがって、DockPanel.Dock親を持たない要素にDockPanelを設定した場合、エラーや例外は発生せず、DockPanelによって使用されないグローバル プロパティ値が作成されます。

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

WPF の添付プロパティには、CLR 名前空間の外部からプロパティが設定される可能性があるため、一般的な CLR get および set ラッパー メソッドはありません。 XAML プロセッサが XAML の解析時にこれらの値を設定できるようにするには、添付プロパティを定義するクラスは、 Get<property name> および Set<property name>の形式で専用アクセサー メソッドを実装する必要があります。

次の例に示すように、専用アクセサー メソッドを使用して、コード内の添付プロパティを取得および設定することもできます。 この例では、 myTextBoxTextBox クラスのインスタンスです。

DockPanel myDockPanel = new();
TextBox myTextBox = new();
myTextBox.Text = "Enter text";

// Add child element to the DockPanel.
myDockPanel.Children.Add(myTextBox);

// Set the attached property value.
DockPanel.SetDock(myTextBox, Dock.Top);
Dim myDockPanel As DockPanel = New DockPanel()
Dim myTextBox As TextBox = New TextBox()
myTextBox.Text = "Enter text"

' Add child element to the DockPanel.
myDockPanel.Children.Add(myTextBox)

' Set the attached property value.
DockPanel.SetDock(myTextBox, Dock.Top)

myTextBoxの子要素としてmyDockPanelを追加しない場合、SetDockを呼び出しても例外が発生したり、影響を受けたりすることはありません。 DockPanel.Dockの子要素に設定されたDockPanel値のみがレンダリングに影響を与え、子要素をDockPanelに追加する前または後に値を設定した場合でも、レンダリングは同じになります。

コードの観点から見ると、添付プロパティは、プロパティ アクセサーではなくメソッド アクセサーを持つバッキング フィールドに似ています。これらのオブジェクトに対して最初に定義する必要なく、任意のオブジェクトに設定できます。

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

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

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

カスタム添付プロパティ

添付プロパティを作成する場合

添付プロパティを作成すると、次の場合に便利です。

  • 定義クラス以外のクラスで使用できるプロパティ設定メカニズムが必要です。 一般的なシナリオは、UI レイアウトです。たとえば、 DockPanel.DockPanel.ZIndexCanvas.Top はすべて既存のレイアウト プロパティの例です。 レイアウト シナリオでは、レイアウト制御要素の子要素は、レイアウトの要件をレイアウトの親に表現し、親によって定義された添付プロパティの値を設定できます。

  • クラスの 1 つがサービスを表し、他のクラスでサービスをより透過的に統合する必要があります。

  • プロパティ ウィンドウでプロパティを編集する機能など、Visual Studio WPF デザイナーのサポートが必要です。 詳細については、「コントロールの作成の概要」を参照してください。

  • プロパティ値の継承を使用したい。

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

クラスが他の型でのみ使用する添付プロパティを定義している場合、クラスは DependencyObjectから派生する必要はありません。 それ以外の場合は、DependencyObjectからクラスを派生させ、添付プロパティを依存関係プロパティにもする WPF モデルに従います。

public static readonly型のDependencyProperty フィールドを宣言して、定義クラスの依存関係として添付プロパティを定義します。 次に、 RegisterAttached メソッドの戻り値を、 依存関係プロパティ識別子とも呼ばれるフィールドに割り当てます。 識別子フィールドに <property name>Property名前を付けることで、フィールドを表すプロパティと区別する WPF プロパティの名前付け規則に従います。 また、静的な Get<property name> メソッドと Set<property name> アクセサー メソッドを指定します。これにより、プロパティ システムは添付プロパティにアクセスできます。

次の例では、 RegisterAttached メソッドを使用して依存関係プロパティを登録する方法と、アクセサー メソッドを定義する方法を示します。 この例では、添付プロパティの名前が HasFishされているため、識別子フィールドの名前は HasFishProperty、アクセサー メソッドの名前は GetHasFish および SetHasFish です。

public class Aquarium : UIElement
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata.
    public static readonly DependencyProperty HasFishProperty = 
        DependencyProperty.RegisterAttached(
      "HasFish",
      typeof(bool),
      typeof(Aquarium),
      new FrameworkPropertyMetadata(defaultValue: false,
          flags: FrameworkPropertyMetadataOptions.AffectsRender)
    );

    // Declare a get accessor method.
    public static bool GetHasFish(UIElement target) =>
        (bool)target.GetValue(HasFishProperty);

    // Declare a set accessor method.
    public static void SetHasFish(UIElement target, bool value) =>
        target.SetValue(HasFishProperty, value);
}
Public Class Aquarium
    Inherits UIElement

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata.
    Public Shared ReadOnly HasFishProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("HasFish", GetType(Boolean), GetType(Aquarium),
            New FrameworkPropertyMetadata(defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.AffectsRender))

    ' Declare a get accessor method.
    Public Shared Function GetHasFish(target As UIElement) As Boolean
        Return target.GetValue(HasFishProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetHasFish(target As UIElement, value As Boolean)
        target.SetValue(HasFishProperty, value)
    End Sub

End Class

「Get アクセサー」はプロパティにアクセスするためのメソッドです。

get アクセサー メソッドのシグネチャは public static object Get<property name>(DependencyObject target) で、次のようになります。

  • target は、添付プロパティの読み取り元となる DependencyObject です。 target型は、DependencyObjectよりも具体的にすることができます。 たとえば、DockPanel.GetDock アクセサー メソッドは、添付プロパティがtargetインスタンスで設定されることを意図しているため、UIElementUIElementとして型指定します。 UiElement DependencyObjectから間接的に派生します。
  • 戻り値の型は、 objectよりも具体的にすることができます。 たとえば、戻り値はGetDock列挙体である必要があるため、Dock メソッドは戻り値をDockとして型指定します。

添付プロパティの get アクセサーは、Visual Studio や Blend for Visual Studio などのデザイン ツールでのデータ バインディングのサポートに必要です。

Set アクセサー

set アクセサー メソッドのシグネチャは public static void Set<property name>(DependencyObject target, object value) で、次のようになります。

  • target は、添付プロパティが書き込まれる DependencyObject です。 target型は、DependencyObjectよりも具体的にすることができます。 たとえば、添付プロパティはSetDockインスタンスに設定することを意図しているため、targetメソッドはUIElementUIElementとして型指定します。 UiElement DependencyObjectから間接的に派生します。
  • value型は、objectよりも具体的にすることができます。 たとえば、 SetDock メソッドには Dock 値が必要です。 XAML ローダーは、添付プロパティ値を表すマークアップ文字列から value 型を生成できる必要があります。 そのため、使用する型の型変換、値シリアライザー、またはマークアップ拡張のサポートが必要です。

添付プロパティ属性

WPF では、リフレクション プロセスおよびリフレクションのコンシューマーやプロパティ情報 (デザイナーなど) に添付プロパティに関する情報を提供するいくつかの .NET 属性を定義します。 デザイナーは、WPF で定義された .NET 属性を使用してプロパティ ウィンドウに表示されるプロパティを制限し、すべての添付プロパティのグローバル リストを持つユーザーを圧倒しないようにします。 これらの属性は、独自のカスタム添付プロパティに適用することを検討してください。 .NET 属性の目的と構文については、次のリファレンス ページで説明します。

詳細情報

  • 添付プロパティの作成の詳細については、「添付プロパティ の登録」を参照してください。
  • 依存関係プロパティと添付プロパティの詳細な使用シナリオについては、「 カスタム依存関係プロパティ」を参照してください。
  • 添付プロパティと依存関係プロパティの両方としてプロパティを登録し、従来のプロパティ ラッパーを含めることができます。 この方法では、プロパティ ラッパーを使用して要素にプロパティを設定したり、XAML 添付プロパティ構文を使用して他の要素にプロパティを設定したりすることもできます。 例については、FrameworkElement.FlowDirectionを参照してください。

こちらも参照ください