依存関係プロパティのメタデータ (WPF .NET)

Windows Presentation Foundation (WPF) プロパティ システムには、依存関係プロパティ メタデータ レポート システムが含まれています。 メタデータ レポート システムを通じて使用できる情報は、リフレクションや一般的な共通言語ランタイム (CLR) の特性から得られる以上のものです。 依存関係プロパティを登録する場合は、メタデータを作成して割り当てるオプションがあります。 依存関係プロパティを定義するクラスから派生させる場合は、継承された依存関係プロパティのメタデータをオーバーライドできます。 また、依存関係プロパティの所有者としてクラスを追加する場合は、継承された依存関係プロパティのメタデータをオーバーライドできます。

前提条件

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

メタデータの使用方法

依存関係プロパティ メタデータに対してクエリを実行して、依存関係プロパティの特性を確認できます。 プロパティ システムでは、依存関係プロパティを処理するときに、そのメタデータにアクセスします。 依存関係プロパティのメタデータ オブジェクトには、次の種類の情報が含まれています。

  • 依存関係プロパティの既定値。これは、ローカル、スタイル、継承値など、他の値が適用されない場合にプロパティ システムによって設定されます。 依存関係プロパティ値の実行時割り当て時の値の優先順位について詳しくは、「依存関係プロパティ値の優先順位」を参照してください。

  • 所有者の種類に対する強制値コールバックとプロパティ変更コールバックへの参照。 public アクセス修飾子がある、または許可されたアクセス スコープ内にあるコールバックへの参照のみを取得できます。 依存関係プロパティのコールバックの詳細については、「依存関係プロパティのコールバックと検証」を参照してください。

  • WPF フレームワーク レベルの依存関係プロパティの特性 (依存関係プロパティが WPF フレームワーク プロパティの場合)。 フレームワーク レイアウト エンジンやプロパティ継承ロジックなどの WPF プロセスでは、WPF フレームワーク レベルのメタデータに対してクエリを実行します。 詳細については、「フレームワーク プロパティ メタデータ」を参照してください。

メタデータ API

PropertyMetadata クラスには、プロパティ システムによって使用されるメタデータのほとんどが格納されます。 メタデータ インスタンスは、以下を使用して作成および割り当てることができます。

  • プロパティ システムに依存関係プロパティを登録する型。

  • 依存関係プロパティを定義するクラスから継承する型。

  • 依存関係プロパティの所有者として、それ自体を追加する型。

型でメタデータを指定せずに依存関係プロパティを登録する場合、プロパティ システムでは、その型の既定値を持つ PropertyMetadata オブジェクトを依存関係プロパティに割り当てます。

依存関係プロパティのメタデータを取得するには、DependencyProperty 識別子で GetMetadata オーバーロードの 1 つを呼び出します。 メタデータは PropertyMetadata オブジェクトとして返されます。

PropertyMetadata から派生したより具体的なメタデータ クラスは、さまざまなアーキテクチャ領域に存在します。 たとえば、UIPropertyMetadata ではアニメーション レポートがサポートされ、FrameworkPropertyMetadata では WPF フレームワーク プロパティがサポートされます。 依存関係プロパティは、PropertyMetadata 派生クラスに登録することもできます。 GetMetadata からは PropertyMetadata オブジェクトが返されますが、該当する場合は、派生型にキャストして、型固有のプロパティを調べることができます。

FrameworkPropertyMetadata によって公開されるプロパティ特性は、''フラグ'' と呼ばれる場合があります。 FrameworkPropertyMetadata インスタンスを作成する場合は、列挙型 FrameworkPropertyMetadataOptions のインスタンスを FrameworkPropertyMetadata コンストラクターに渡すオプションがあります。 FrameworkPropertyMetadataOptions では、メタデータ フラグをビットごとの組み合わせで指定できます。 FrameworkPropertyMetadata では FrameworkPropertyMetadataOptions を使用して、コンストラクター シグネチャを妥当な長さに保ちます。 依存関係プロパティの登録時に、FrameworkPropertyMetadataOptions に設定したメタデータ フラグは、メタデータ特性のクエリをより直感的に行うために、フラグのビットごとの組み合わせではなく、Boolean プロパティとして FrameworkPropertyMetadata 内に公開されます。

新しいメタデータをオーバーライドまたは作成しますか?

依存関係プロパティを継承する場合は、そのメタデータをオーバーライドして依存関係プロパティの特性を変更するオプションがあります。 しかし、メタデータをオーバーライドすることで、必ずしも依存関係プロパティのシナリオを実行できるとは限りません。また、新しいメタデータでクラスにカスタム依存関係プロパティを定義する必要がある場合があります。 カスタム依存関係プロパティには、WPF 型で定義された依存関係プロパティと同じ機能があります。 詳細については、「カスタム依存関係プロパティ」を参照してください。

オーバーライドできない依存関係プロパティの特性の 1 つは、その値の型です。 継承された依存関係プロパティの動作が目的のものとほぼ一致するものの、シナリオで別の値の型が必要な場合は、カスタム依存関係プロパティの実装を検討してください。 派生クラスの型変換または他の実装を通じて、プロパティ値をリンクできる場合があります。

メタデータをオーバーライドするシナリオ

既存の依存関係プロパティ メタデータをオーバーライドするシナリオの例を以下に示します。

  • 既定値の変更。これは一般的なシナリオです。

  • プロパティ変更コールバックの変更または追加。これは、継承された依存関係プロパティが、基本実装とは異なる方法で他の依存関係プロパティとやりとりする場合に必要になる可能性があります。 コードとマークアップの両方をサポートするプログラミング モデルの特性の 1 つは、プロパティ値が任意の順序で設定される可能性があることです。 この要因は、プロパティ変更コールバックの実装方法に影響する可能性があります。 詳細については、「依存関係プロパティのコールバックと検証」を参照してください。

  • WPF フレームワーク プロパティ メタデータ オプションの変更。 通常、メタデータ オプションは新しい依存関係プロパティの登録時に設定されますが、OverrideMetadata または AddOwner 呼び出しで再指定できます。 フレームワーク プロパティ メタデータのオーバーライドの詳細については、「FrameworkPropertyMetadata の指定」を参照してください。 依存関係プロパティを登録するときにフレームワーク プロパティ メタデータ オプションを設定する方法については、「カスタム依存関係プロパティ」を参照してください。

注意

検証コールバックはメタデータの一部ではないため、メタデータをオーバーライドして変更することはできません。 詳細については、「値検証コールバック」を参照してください。

メタデータのオーバーライド

新しい依存関係プロパティを実装する場合は、Register メソッドのオーバーロードを使用して、そのメタデータを設定できます。 クラスで依存関係プロパティが継承される場合は、OverrideMetadata メソッドを使用して継承されたメタデータ値をオーバーライドできます。 たとえば、OverrideMetadata を使用して型固有の値を設定できます。 詳細およびコード サンプルについては、「依存関係プロパティのメタデータをオーバーライドする」を参照してください。

WPF 依存関係プロパティの例として、Focusable があります。 FrameworkElement クラスでは Focusable を登録します。 Control クラスは FrameworkElement から派生し、Focusable 依存関係プロパティを継承し、継承されたプロパティ メタデータをオーバーライドします。 オーバーライドにより、既定のプロパティ値が false から true に変更されますが、他の継承されたメタデータ値は保持されます。

ほとんどの既存の依存関係プロパティは仮想プロパティではないため、継承された実装では既存のメンバーがシャドウされます。 メタデータ特性をオーバーライドすると、新しいメタデータ値によって元の値が置き換えられるか、マージされます。

  • DefaultValue の場合、新しい値によって既存の既定値が置き換えられます。 オーバーライド メタデータで DefaultValue を指定しないと、DefaultValue の値は、それをメタデータで指定した最も近い先祖のものになります。

  • PropertyChangedCallback の場合、既定のマージ ロジックでは PropertyChangedCallback の値がすべてテーブルに格納され、プロパティの変更時にすべて呼び出されます。 コールバックの順序は、階層内の基本クラスによって登録されたコールバックが最初に実行されるクラスの深さによって決まります。

  • CoerceValueCallback の場合、新しい値によって既存の CoerceValueCallback の値が置き換えられます。 オーバーライド メタデータで CoerceValueCallback を指定しないと、CoerceValueCallback の値は、それをメタデータで指定した最も近い先祖のものになります。

注意

既定のマージ ロジックは、Merge メソッドによって実装されます。 依存関係プロパティを継承する派生クラスでは、そのクラスで Merge をオーバーライドすることで、カスタム マージ ロジックを指定できます。

クラスを所有者として追加する

別のクラス階層に登録されている依存関係プロパティを "継承" するには、AddOwner メソッドを使用します。 このメソッドは通常、追加するクラスが、依存関係プロパティを登録した型から派生されていない場合に使用されます。 AddOwner 呼び出しでは、追加クラスで、継承された依存関係プロパティの型固有のメタデータを作成して割り当てることができます。 プロパティ システムに完全に参加するには、コードとマークアップを使用して、追加するクラスでこれらのパブリック メンバーを実装する必要があります。

  • 依存関係プロパティの識別子フィールド。 依存関係プロパティ識別子の値は、AddOwner 呼び出しの戻り値です。 このフィールドは、public static readonly 型の DependencyProperty である必要があります。

  • get および set アクセサーを実装する CLR ラッパー。 プロパティ ラッパーを使用することで、依存関係プロパティのコンシューマーは、他の CLR プロパティと同様に、依存関係プロパティの値を取得または設定できます。 get および set アクセサーでは、DependencyObject.GetValueDependencyObject.SetValue の呼び出しを介して基になるプロパティ システムとやりとりし、依存関係プロパティ識別子をパラメーターとして渡します。 カスタム依存関係プロパティを登録する場合と同じ方法でラッパーを実装します。 詳細については、「カスタム依存関係プロパティ」を参照してください

AddOwner を呼び出すクラスで継承された依存関係プロパティのオブジェクト モデルを公開するための要件は、新しいカスタム依存関係プロパティを定義するクラスと同じです。 詳細については、「依存関係プロパティの所有者の種類を追加する」を参照してください。

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

WPF では、WPF 型のほとんどの UI 関連の添付プロパティが、依存関係プロパティとして実装されます。 依存関係プロパティとして実装される添付プロパティでは、派生クラスでオーバーライドできるメタデータなど、依存関係プロパティの概念がサポートされます。 添付プロパティのメタデータは、一般的に依存関係プロパティと違いはありません。 オーバーライドするクラスのインスタンスで、継承された添付プロパティの既定値、プロパティ変更コールバック、および WPF フレームワーク プロパティをオーバーライドできます。 詳細については、「添付プロパティ メタデータ」を参照してください

注意

メタデータで Inherits を指定する場合は、必ず RegisterAttached を使用してプロパティを登録します。 プロパティ値の継承は、非添付依存関係プロパティに対して機能しているように見えることがありますが、ランタイム ツリーでの特定の objectオブジェクト区分を介した非添付プロパティの値の継承動作は定義されていません。 Inherits プロパティは、非添付プロパティには関係ありません。 詳細については、「RegisterAttached(String, Type, Type, PropertyMetadata)」、および「Inherits」の解説セクションを参照してください。

添付プロパティの所有者としてクラスを追加する

添付プロパティを別のクラスから継承するものの、それをクラスで非添付依存関係プロパティとして公開するには、次のようにします。

  • AddOwner を呼び出して、添付依存関係プロパティの所有者としてクラスを追加する。

  • 依存関係プロパティ識別子として使用するために、public static readonly フィールドに AddOwner 呼び出しの戻り値を割り当てる。

  • CLR ラッパーを定義する。これにより、プロパティがクラス メンバーとして追加され、非添付プロパティの使用がサポートされます。

関連項目