(カスタム)依存関係プロパティとWPFの添付プロパティの違いは何ですか?それぞれの用途は何ですか?実装は通常どのように異なりますか?
回答:
この件に関するドキュメントはほとんど、またはまったく見つからなかったため、ソースコードをざっと見てみましたが、ここで答えを示します。
依存関係プロパティを通常のプロパティと添付プロパティとして登録することには、「哲学的」なプロパティ 以外に違いがあります(通常のプロパティは宣言型とその派生型で使用することを意図しており、添付プロパティは任意の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
れたのみの新しいインスタンスですDefaultValue
。OverrideMetadata
提供されたメタデータを実際に使用する後続の呼び出しのみ。
主な実用的な違いは、通常のプロパティの場合、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、これらの構文の使用を支配する唯一のルールは次のとおりです。
これらの条件を満たすことにより、バッキング依存関係プロパティが通常として登録されているか、アタッチされているかに関係なく、対応する構文を使用できます。
ここで説明されている誤解は、チュートリアルの大部分(ストックのVisual Studioコードスニペットと共に)が通常の依存関係プロパティにCLRプロパティを使用し、アタッチされたプロパティにget / setアクセサーを使用するように指示しているという事実が原因です。しかし、両方を同時に使用することを妨げるものは何もないため、好きな構文を使用できます。
添付プロパティは、依存関係プロパティの一種です。違いは、それらの使用方法にあります。
添付プロパティを使用すると、プロパティは、使用されているクラスとは異なるクラスで定義されます。これは通常、レイアウトに使用されます。良い例はPanel.ZIndexまたはGrid.Rowです。これをコントロール(つまり、ボタン)に適用しますが、実際にはPanelまたはGridで定義されています。プロパティはボタンのインスタンスに「添付」されます。
これにより、たとえば、コンテナーは任意のUIelementで使用できるプロパティを作成できます。
実装の違いについては、基本的には、プロパティを定義するときにRegisterとRegisterAttachedを使用するだけです。
添付プロパティは、特別な種類のDependencyPropertiesです。これらを使用すると、この値について何も知らないオブジェクトに値をアタッチできます。この概念の良い例は、レイアウトパネルです。各レイアウトパネルは、子要素を配置するために異なるデータを必要とします。CanvasにはTopとLeftが、DockPanelにはDockが必要です。独自のレイアウトパネルを作成できるため、リストは無限です。つまり、すべてのWPFコントロールにこれらのプロパティをすべて設定することはできません。ソリューションは添付プロパティです。これらは、特定のコンテキストで別のコントロールからのデータを必要とするコントロールによって定義されます。たとえば、親レイアウトパネルによって配置される要素。