.net 什么';WPF中依赖属性和附加属性之间的区别是什么?
WPF中的(自定义)依赖属性和附加属性之间有什么区别?每个都有什么用途?实现通常有何不同?附加属性是一种依赖属性。区别在于它们的使用方式 使用附加属性时,该属性是在一个类上定义的,而该类与使用该属性的类不同。这通常用于布局。很好的例子是Panel.ZIndex或Grid.Row-您可以将其应用于控件(即:按钮),但它实际上是在Panel或Grid中定义的。属性“附加”到按钮的实例 例如,这允许容器创建可用于任何UIelement的属性.net 什么';WPF中依赖属性和附加属性之间的区别是什么?,.net,wpf,dependency-properties,attached-properties,.net,Wpf,Dependency Properties,Attached Properties,WPF中的(自定义)依赖属性和附加属性之间有什么区别?每个都有什么用途?实现通常有何不同?附加属性是一种依赖属性。区别在于它们的使用方式 使用附加属性时,该属性是在一个类上定义的,而该类与使用该属性的类不同。这通常用于布局。很好的例子是Panel.ZIndex或Grid.Row-您可以将其应用于控件(即:按钮),但它实际上是在Panel或Grid中定义的。属性“附加”到按钮的实例 例如,这允许容器创建可用于任何UIelement的属性 至于实现上的差异——在定义属性时,基本上只是使用Regist
至于实现上的差异——在定义属性时,基本上只是使用Register和RegisterAttached的问题。附加的属性基本上是针对容器元素的。例如,如果您有一个grid和grid.row,现在这被认为是一个grid元素的附加属性。您也可以使用它属性,以设置其在网格中的位置 依赖性属性类似于该属性基本上属于其他类,并在其他类中使用。 就像你有一个长方形
此处高度和宽度是矩形的常规属性,但左侧和顶部是从属属性,因为它属于画布类。附加属性是一种特殊的从属属性。它们允许您将值附加到对该值一无所知的对象。 这一概念的一个很好的例子是布局面板。每个布局面板需要不同的数据来对齐其子元素。画布需要顶部和左侧,DockPanel需要Dock等。因为您可以编写自己的布局面板,所以列表是无限的。所以你看,不可能在所有WPF控件上都有这些属性。
解决方案是附加的属性。它们由需要来自特定上下文中另一个控件的数据的控件定义。例如,由父布局面板对齐的元素。我认为可以在类本身中定义附加属性,也可以在另一个类中定义附加属性。我们总是可以使用附加属性来扩展标准的microsoft控件。但是依赖属性,您可以在自己的自定义控件中定义它。e、 可以从标准控件继承控件,并在自己的控件中定义依赖项属性并使用它。这相当于定义附加属性,并在标准控件中使用此附加属性。Abstract 因为我几乎没有找到关于这个问题的文档,所以我花了一些时间来研究这个问题,但这里有一个答案 将依赖项属性注册为常规属性和附加属性(而不是“哲学”属性)是有区别的(常规属性旨在由声明类型及其派生类型使用,附加属性旨在用作任意
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
});
结论
常规依赖项属性和附加依赖项属性之间的关键(也是唯一)区别是通过属性提供的默认元数据。本节甚至提到了这一点:
对于非附加属性,此属性返回的元数据类型不能强制转换为类型的派生类型,即使该属性最初是使用派生元数据类型注册的。如果希望原始注册的元数据包括其原始可能派生的元数据类型,请改为调用,将原始注册类型作为参数传递
对于附加属性,此属性返回的元数据类型将与原始注册方法中给定的类型匹配
这在提供的代码中清晰可见。注册方法中也隐藏了一些提示,即对于RegisterAttached
元数据参数命名为defaultMetadata
,而对于Register
元数据参数命名为typeMetadata
。对于附加属性,提供的元数据将成为默认元数据。但是,对于常规属性,默认元数据始终是PropertyMetadata
的新实例,仅设置了DefaultValue
(从提供的元数据或自动设置)。只有对OverrideMetadata
的后续调用实际使用提供的元数据
后果
主要的实际区别是,在常规属性的情况下,强制值回调
和属性更改回调
仅适用于从声明为所有者类型的类型派生的类型,对于附加属性,它们适用于所有类型。例如,在这种情况下:
var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");
登记的
<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" />
<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />