添付プロパティの概要 (WPF .NET)

添付プロパティは、Extensible Application Markup Language (XAML) の概念です。 添付プロパティを使用すると、要素によってそのオブジェクト モデルに追加のプロパティが定義されていない場合でも、DependencyObject から派生した任意の XAML 要素に追加のプロパティと値のペアを設定できます。 追加のプロパティにはグローバルにアクセスできます。 添付プロパティは通常、従来のプロパティ ラッパーがない特殊な形式の依存関係プロパティとして定義されます。

重要

.NET 7 と .NET 6 用のデスクトップ ガイド ドキュメントは作成中です。

必須コンポーネント

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

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

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

XAML での添付プロパティ

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

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

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

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

WPF での添付プロパティ

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

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

オブジェクトで添付プロパティ値を設定できますが、値を設定すると具体的な成果が得られたり、値が別のオブジェクトによって使用されるという意味ではありません。 添付プロパティの主な目的は、さまざまなクラス階層と論理関係からのオブジェクトで、添付プロパティを定義する型に共通する情報をレポートする方法を提供することです。 添付プロパティを使用する場合は通常、これらのいずれかのモデルに従います。

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

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

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

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

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

WPF の添付プロパティには一般的な CLR get および set ラッパー メソッドはありません。これは、CLR 名前空間の外部からプロパティが設定される可能性があるためです。 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)

myTextBoxmyDockPanel の子要素として追加しない場合は、SetDock を呼び出したときに例外は発生せず、何の影響もありません。 DockPanel の子要素に設定された DockPanel.Dock 値のみがレンダリングに影響する可能性があります。また、子要素を DockPanel に追加する前と後のどちらに値を設定した場合でも、レンダリングは同じになります。

コードの観点からは、添付プロパティは、プロパティ アクセサーではなくメソッド アクセサーがあるバッキング フィールドのようなものです。また、それらのオブジェクトに対して最初に定義しなくても、任意のオブジェクトに設定できます。

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

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

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

カスタム添付プロパティ

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

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

  • 定義するクラス以外のクラスで使用できるプロパティ設定機構が必要である。 一般的なシナリオは、UI レイアウトの場合です。たとえば、DockPanel.DockPanel.ZIndex、および Canvas.Topはすべて既存のレイアウト プロパティの例です。 レイアウト シナリオでは、レイアウト制御要素の子要素で、レイアウトの要件をそれらのレイアウトの親に示し、親によって定義されている添付プロパティの値を設定できます。

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

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

  • プロパティ値の継承を使用する必要がある。

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

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

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

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

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 の型は UIElement となります。これは、添付プロパティが UIElement インスタンスで設定されることになっているからです。 UiElementDependencyObject から間接的に派生します 。
  • 戻り値の型は、object よりも具体的なものにすることができます。 たとえば、GetDock メソッドでは、戻り値の型は Dock となります。これは、戻り値が Dock 列挙型である必要があるためです。

注意

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

set アクセサー

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

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

添付プロパティの属性

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

詳細情報

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

関連項目