WPFの依存関係プロパティと添付プロパティの違いは何ですか?


回答:


20

概要

この件に関するドキュメントはほとんど、またはまったく見つからなかったため、ソースコードをざっと見てみましたが、ここで答えを示します。

依存関係プロパティを通常のプロパティと添付プロパティとして登録することには、「哲学的」なプロパティ 以外に違いがあります(通常のプロパティは宣言型とその派生型で使用することを意図しており、添付プロパティは任意のDependencyObject インスタンスの拡張)。「哲学的」。@ MarqueIVが@ReedCopseyの回答へのコメントで気づいたように、通常のプロパティは任意のDependencyObjectインスタンスでも使用できます。

さらに、誤解を招くので、添付プロパティが「依存関係プロパティのタイプ」であるという他の回答に同意する必要があります。依存関係プロパティの「タイプ」はありません。フレームワークは、プロパティが添付として登録されているかどうかを気にしません-判断することもできません(この情報は関係がないため、記録されないという意味で)。実際、すべてのプロパティは、それらが添付されたプロパティであるかのように登録されますが、通常のプロパティの場合、それらの動作をわずかに変更する追加の処理が行われます。

コード抜粋

自分でソースコードを確認する手間を省くために、ここでは、何が起きているかを簡単に説明します。

メタデータを指定せずにプロパティを登録するときは、

DependencyProperty.Register(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass))

呼び出しとまったく同じ結果が得られます

DependencyProperty.RegisterAttached(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass))

ただし、メタデータを指定するときは、

DependencyProperty.Register(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass),
    typeMetadata: new FrameworkPropertyMetadata
    {
        CoerceValueCallback = CoerceCallback,
        DefaultValue = "default value",
        PropertyChangedCallback = ChangedCallback
    });

呼び出すのと同じです

var property = DependencyProperty.RegisterAttached(
    name: "MyProperty",
    propertyType: typeof(object),
    ownerType: typeof(MyClass),
    defaultMetadata: new PropertyMetadata
    {
        DefaultValue = "default value",
    });
property.OverrideMetadata(
    forType: typeof(MyClass),
    typeMetadata: new FrameworkPropertyMetadata
    {
        CoerceValueCallback = CoerceCallback,
        DefaultValue = "default value",
        PropertyChangedCallback = ChangedCallback
    });

結論

通常の依存関係プロパティと添付された依存関係プロパティの主な(そして唯一の)違いは、DependencyProperty.DefaultMetadataプロパティを通じて利用可能なデフォルトのメタデータです。これについては、「備考」セクションでも触れています。

非アタッチプロパティの場合、このプロパティによって返されたメタデータタイプは、プロパティが最初に派生メタデータタイプで登録されていたとしても、PropertyMetadataタイプの派生タイプにキャストできません。元の登録されたメタデータタイプを含む可能性のある元のメタデータが必要な場合は、代わりにGetMetadata(Type)を呼び出して、元の登録タイプをパラメーターとして渡します。

添付プロパティの場合、このプロパティによって返されるメタデータのタイプは、元のRegisterAttached登録メソッドで指定されたタイプと一致します。

これは、提供されたコードではっきりと確認できます。リトルヒントはまたのために、すなわち、登録方法に隠されているRegisterAttachedメタデータパラメータの名前はdefaultMetadataのためのに対し、Registerそれが命名されますtypeMetadata。添付プロパティの場合、提供されたメタデータがデフォルトのメタデータになります。ただし、通常のプロパティの場合、デフォルトのメタデータは常に(提供されたメタデータから、または自動的に)設定さPropertyMetadataれたのみの新しいインスタンスですDefaultValueOverrideMetadata提供されたメタデータを実際に使用する後続の呼び出しのみ。

結果

主な実用的な違いは、通常のプロパティの場合、CoerceValueCallbackおよびPropertyChangedCallbackは、所有者タイプとして宣言されたタイプから派生したタイプにのみ適用でき、添付プロパティにはすべてのタイプに適用できるということです。このシナリオの例:

var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");

プロパティが添付プロパティとして登録されている場合は、registered PropertyChangedCallback が呼び出されますが、通常のプロパティとして登録されている場合は呼び出されません。同じことが行きCoerceValueCallbackます。

二次的な違いOverrideMetadataは、提供された型がから派生することを要求するという事実から生じDependencyObjectます。実際には、通常のプロパティの所有者タイプはから派生する必要がありますDependencyObject、添付プロパティの場合は任意のタイプ(静的クラス、構造体、列挙型、デリゲートなどを含む)にすることができます。

補足

@MarqueIVの提案に加えて、通常のプロパティと添付プロパティはXAMLで使用できる方法が異なるという意見に出くわすことがあります。つまり、その通常のプロパティには、アタッチされたプロパティに必要な明示的な名前構文とは対照的に、暗黙的な名前構文が必要です。これは技術的には正しくありませんが、実際には通常そうです。明確にするために:

<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" /> 

<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />

純粋なXAML、これらの構文の使用を支配する唯一のルールは次のとおりです。

  • この要素が表すクラスにその名前のCLRプロパティがある場合に限り、暗黙的な名前構文を要素で使用できます。
  • フルネームの最初の部分で指定されたクラスが、フルネームの2番目の部分と一致する名前を持つ適切な静的get / setメソッド(アクセサーと呼ばれる)を公開する場合にのみ、明示的な名前構文を要素で使用できます。

これらの条件を満たすことにより、バッキング依存関係プロパティが通常として登録されているか、アタッチされているかに関係なく、対応する構文を使用できます。

ここで説明されている誤解は、チュートリアルの大部分(ストックのVisual Studioコードスニペットと共に)が通常の依存関係プロパティにCLRプロパティを使用し、アタッチされたプロパティにget / setアクセサーを使用するように指示しているという事実が原因です。しかし、両方を同時に使用することを妨げるものは何もないため、好きな構文を使用できます。


71

添付プロパティは、依存関係プロパティの一種です。違いは、それらの使用方法にあります。

添付プロパティを使用すると、プロパティは、使用されているクラスとは異なるクラスで定義されます。これは通常、レイアウトに使用されます。良い例はPanel.ZIndexまたはGrid.Rowです。これをコントロール(つまり、ボタン)に適用しますが、実際にはPanelまたはGridで定義されています。プロパティはボタンのインスタンスに「添付」されます。

これにより、たとえば、コンテナーは任意のUIelementで使用できるプロパティを作成できます。

実装の違いについては、基本的には、プロパティを定義するときにRegisterとRegisterAttachedを使用するだけです。


10
しかし、正確な違いは何ですか?私が見たものから、コードを介して非アタッチ可能なプロパティを別のプロパティにアタッチできます(ただし、これはXAMLでブロックされていると思います。)おそらくそれが違いですか?
Mark A. Donohoe

5

添付プロパティは、基本的にはコンテナー要素を対象としています。グリッドがあり、grid.rowがある場合、これはグリッド要素の添付プロパティと見なされます。また、このプロパティをtexbox、buttonなどで使用して、グリッドに配置します。

依存関係プロパティは、プロパティが基本的に他のクラスに属し、他のクラスで使用されるようなものです。例:ここに長方形があるように、高さと幅は長方形の通常のプロパティですが、左と上部はCanvassクラスに属しているため、依存関係プロパティです。


-1

添付プロパティは、特別な種類のDependencyPropertiesです。これらを使用すると、この値について何も知らないオブジェクトに値をアタッチできます。この概念の良い例は、レイアウトパネルです。各レイアウトパネルは、子要素を配置するために異なるデータを必要とします。CanvasにはTopとLeftが、DockPanelにはDockが必要です。独自のレイアウトパネルを作成できるため、リストは無限です。つまり、すべてのWPFコントロールにこれらのプロパティをすべて設定することはできません。ソリューションは添付プロパティです。これらは、特定のコンテキストで別のコントロールからのデータを必要とするコントロールによって定義されます。たとえば、親レイアウトパネルによって配置される要素。


-1

添付プロパティをクラス自体で定義することも、別のクラスで定義することもできると思います。添付プロパティを使用して、標準のMicrosoftコントロールを拡張できます。しかし、依存関係プロパティは、独自のカスタムコントロールで定義します。たとえば、標準のコントロールからコントロールを継承し、独自のコントロールで依存関係プロパティを定義して使用できます。これは、添付プロパティを定義することと同じであり、この添付プロパティを標準コントロールで使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.