WPF 中的依赖属性和附加属性有什么区别? [英] What's the difference between a dependency property and an attached property in WPF?

查看:34
本文介绍了WPF 中的依赖属性和附加属性有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

WPF 中的(自定义)依赖属性和附加属性有什么区别?各有什么用途?这些实现通常有何不同?

What's the difference between a (custom) dependency property and an attached property in WPF? What are the uses for each? How do the implementations typically differ?

推荐答案

摘要

由于我几乎没有发现有关此事的文档,因此我对 源代码,但这里有一个答案.

将依赖属性注册为常规属性和附加属性之间存在差异,而不是哲学"属性(常规属性旨在由声明类型及其派生类型、附加属性使用旨在用作任意 DependencyObject 实例的扩展.哲学",因为正如@MarqueIV 在他对@ReedCopsey 的回答的评论中注意到的那样,常规属性也可以与任意 DependencyObject 实例一起使用.

There is a difference between registering a dependency property as a regular and as an attached property, other than a "philosophical" one (regular properties are intended to be used by the declaring type and its deriving types, attached properties are intended to be used as extensions on arbitrary DependencyObject instances). "Philosophical", because, as @MarqueIV noticed in his comment to @ReedCopsey's answer, regular properties can also be used with arbitrary DependencyObject instances.

此外,我不得不不同意其他答案,即附加属性是依赖属性的类型",因为它具有误导性 - 没有任何依赖属性的类型".该框架并不关心该财产是否已注册为附属 - 它甚至无法确定(从某种意义上说,此信息未记录,因为它无关紧要).事实上,所有属性都被注册为附加属性,但在常规属性的情况下,会做一些额外的事情来稍微修改它们的行为.

Moreover, I have to disagree with other answers stating that attached property is "type of dependency property", because it's misleading - there aren't any "types" of dependency properties. The framework doesn't care if the property was registered as attached or not - it's not even possible to determine (in the sense that this information is not recorded, because it's irrelevant). In fact, all properties are registered as if they were attached properties, but in case of regular ones some additional things are done that slightly modify their behavior.

为了省去您自己查看源代码的麻烦,这里有一个经过简化的版本.

To save you the trouble of going through the source code yourself, here's a boiled down version of what happens.

在未指定元数据的情况下注册属性时,调用

When registering a property without metadata specified, calling

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

产生与调用完全相同的结果

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

但是,在指定元数据时,调用

However, when specifying metadata, calling

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 属性.这甚至在 备注部分:

Conclusions

The key (and only) difference between regular and attached dependency properties is the default metadata available through DependencyProperty.DefaultMetadata property. This is even mentioned in the Remarks section:

对于非附加属性,此属性返回的元数据类型无法转换为 PropertyMetadata 类型,即使该属性最初是使用派生元数据类型注册的.如果您想要原始注册的元数据包括其原始可能派生的元数据类型,请调用 GetMetadata(Type) 代替,将原始注册类型作为参数传递.

For nonattached properties, the metadata type returned by this property cannot be cast to derived types of PropertyMetadata type, even if the property was originally registered with a derived metadata type. If you want the originally registered metadata including its original possibly derived metadata type, call GetMetadata(Type) instead, passing the original registering type as a parameter.

对于附加属性,此属性返回的元数据类型将与原始RegisterAttached 注册方法.

For attached properties, the type of the metadata returned by this property will match the type given in the original RegisterAttached registration method.

这在提供的代码中清晰可见.在注册方法中也隐藏了一些小提示,即对于 RegisterAttached,元数据参数被命名为 defaultMetadata,而对于 Register,它被命名为 类型元数据.对于附加属性,提供的元数据成为默认元数据.但是,在常规属性的情况下,默认元数据始终是 PropertyMetadata 的新实例,仅设置了 DefaultValue(来自提供的元数据或自动设置).只有随后对 OverrideMetadata 的调用实际使用了提供的元数据.

This is clearly visible in the provided code. Little hints are also hidden in the registering methods, i.e. for RegisterAttached the metadata parameter is named defaultMetadata, whereas for Register it is named typeMetadata. For attached properties the provided metadata becomes the default metadata. In case of regular properties however, the default metadata is always a fresh instance of PropertyMetadata with only DefaultValue set (either from provided metadata or automatically). Only the subsequent call to OverrideMetadata actually uses the provided metadata.

主要的实际区别在于,对于常规属性,CoerceValueCallbackPropertyChangedCallback 仅适用于从声明为的类型派生的类型所有者类型,对于附加属性,它们适用于所有类型.例如.在这种情况下:

The main practical difference is that in case of regular properties the CoerceValueCallback and PropertyChangedCallback are applicable only for types derived from the type declared as the owner type, and for attached properties they're applicable for all types. E.g. in this scenario:

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

注册的PropertyChangedCallback 如果该属性被注册为附加属性将被调用,但如果它被注册为不会被调用常规财产.CoerceValueCallback 也是如此.

the registered PropertyChangedCallback will be called if the property was registered as an attached property, but will not be called if it was registered as a regular property. Same goes to CoerceValueCallback.

次要差异源于 OverrideMetadata 要求提供的类型派生自 DependencyObject 的事实.实际上,这意味着常规属性的所有者类型必须从DependencyObject 派生,而对于附加属性,可以是任何类型(包括静态类、结构、枚举、委托等).

A secondary difference stems from the fact that OverrideMetadata requires that supplied type derives from DependencyObject. In practice it means that the owner type for regular properties must derive from DependencyObject, whereas for attached properties in can be any type (including static classes, structs, enums, delegates, etc.).

除了@MarqueIV 的建议之外,我还多次遇到这样的观点,即常规属性和附加属性在XAML 中的使用方式不同.即,常规属性需要隐式名称语法,而不是附加属性所需的显式名称语法.这在技术上不正确,尽管在​​实践中通常是这样.为清楚起见:

Besides @MarqueIV's suggestion, on several occasions I've come across opinions that regular and attached properties differ in the way they can be used in XAML. Namely, that regular properties require implicit name syntax as opposed to explicit name syntax required by attached properties. This is technically not true, although in practice it usually is the case. For clarity:

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

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

纯 XAML 中,控制这些语法使用的唯一规则如下:

In pure XAML, the only rules governing the usage of these syntaxes are the following:

  • 可以在元素上使用隐式名称语法当且仅当该元素表示的类具有该名称的 CLR 属性
  • 可以在元素上使用显式名称语法当且仅当由全名的第一部分指定的类公开适当的静态get/set 方法(称为访问器) 名称与全名的第二部分相匹配
  • Implicit name syntax can be used on an element if and only if the class that this element represents has a CLR property of that name
  • Explicit name syntax can be used on an element if and only if the class specified by the first part of the full name exposes appropriate static get/set methods (referred to as accessors) with names matching the second part of the full name

满足这些条件使您能够使用相应的语法,无论支持依赖属性是注册为常规属性还是附加属性.

Satisfying these conditions enables you to use corresponding syntax regardless of whether the backing dependency property was registered as regular or attached.

现在提到的误解是由于绝大多数教程(连同股票 Visual Studio 代码片段)指示您使用 CLR 属性作为常规依赖属性的事实, 并为附加的获取/设置访问器.但是没有什么可以阻止您同时使用这两种语法,让您可以使用您喜欢的任何语法.

Now the mentioned misconception is caused by the fact that vast majority of tutorials (together with stock Visual Studio code snippets) instruct you to use CLR property for regular dependency properties, and get/set accessors for attached ones. But there's nothing stopping you from using both at the same time, allowing you to use whichever syntax you prefer.

这篇关于WPF 中的依赖属性和附加属性有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆