ken*_*ner 87 .net wpf dependency-properties attached-properties
WPF中的(自定义)依赖项属性和附加属性之间有什么区别?每种用途有哪些用途?这些实现通常有何不同?
Ree*_*sey 69
附加属性是一种依赖属性.不同之处在于它们的使用方式.
使用附加属性时,属性是在与其使用的类不同的类上定义的.这通常用于布局.很好的例子是Panel.ZIndex或Grid.Row - 你将它应用于一个控件(即:Button),但它实际上是在Panel或Grid中定义的.该属性"附加"到按钮的实例.
例如,这允许容器创建可以在任何UIelement上使用的属性.
至于实现差异 - 基本上只是在定义属性时使用Register vs. RegisterAttached.
Grx*_*x70 12
由于我发现很少甚至没有关于这个问题的文档,因此需要对源代码进行一些讨论,但这是一个答案.
将依赖属性注册为常规属性和附加属性之间存在差异,而不是"哲学" 属性 (常规属性旨在由声明类型及其派生类型使用,附加属性旨在用作任意DependencyObject
实例上的扩展)."哲学",因为正如@MarqueIV在他对@ReedCopsey答案的评论中所注意到的那样,常规属性也可以用于任意DependencyObject
实例.
此外,我不同意其他答案,说明附加属性是"依赖属性的类型",因为它具有误导性 - 没有任何"类型"的依赖属性.框架并不关心财产是否已注册为附加 - 甚至无法确定(在某种意义上,这些信息未被记录,因为它不相关).实际上,所有属性都被注册为好像它们是附加属性,但是在常规属性的情况下,还会做一些额外的事情来稍微修改它们的行为.
为了省去自己完成源代码的麻烦,这里有一个简单的版本.
注册没有指定元数据的属性时,调用
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
Run Code Online (Sandbox Code Playgroud)
产生与调用完全相同的结果
DependencyProperty.RegisterAttached(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass))
Run Code Online (Sandbox Code Playgroud)
但是,在指定元数据时,调用
DependencyProperty.Register(
name: "MyProperty",
propertyType: typeof(object),
ownerType: typeof(MyClass),
typeMetadata: new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceCallback,
DefaultValue = "default value",
PropertyChangedCallback = ChangedCallback
});
Run Code Online (Sandbox Code Playgroud)
相当于打电话
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
});
Run Code Online (Sandbox Code Playgroud)
常规和附加依赖项属性之间的关键(也是唯一)区别是通过DependencyProperty.DefaultMetadata属性可用的默认元数据.这在备注部分甚至提到:
对于非附加属性,此属性返回的元数据类型无法强制转换为PropertyMetadata类型的派生类型,即使该属性最初是使用派生元数据类型注册的.如果您想要原始注册的元数据(包括其原始可能派生的元数据类型),请调用GetMetadata(Type),将原始注册类型作为参数传递.
对于附加属性,此属性返回的元数据类型将与原始RegisterAttached注册方法中指定的类型匹配.
这在提供的代码中清晰可见.注册方法中也隐藏了一些小提示,即RegisterAttached
元数据参数被命名defaultMetadata
,而Register
它被命名typeMetadata
.对于附加属性,提供的元数据将成为默认元数据.但是,对于常规属性,默认元数据始终是PropertyMetadata
仅具有DefaultValue
set 的新实例(来自提供的元数据或自动).只有后续调用OverrideMetadata
实际使用提供的元数据.
主要的实际区别是,在常规性的情况下,CoerceValueCallback
并PropertyChangedCallback
适用只有从声明为所有者类型类型派生类型,以及附加属性它们适用于所有类型.例如,在这种情况下:
var d = new DependencyObject();
d.SetValue(SomeClass.SomeProperty, "some value");
Run Code Online (Sandbox Code Playgroud)
注册PropertyChangedCallback
将被调用,如果财产被注册为附加属性,但不会被调用,如果它被注册为普通的属性.同样如此CoerceValueCallback
.
次要差异源于OverrideMetadata
需要所提供的类型来源的事实DependencyObject
.在实践中,它意味着常规属性的所有者类型必须派生自DependencyObject
,而附加属性可以是任何类型(包括静态类,结构,枚举,委托等).
除了@ MarqueIV的建议之外,我曾多次发现有关常规属性和附加属性在XAML中的使用方式不同的观点.也就是说,常规属性需要隐式名称语法,而不是附加属性所需的显式名称语法.这在技术上是不正确的,尽管在实践中通常是这种情况.为清楚起见:
<!-- Implicit property name -->
<ns:SomeClass SomeProperty="some value" />
<!-- Explicit property name -->
<DependencyObject ns:SomeClass.SomeProperty="some value" />
Run Code Online (Sandbox Code Playgroud)
在纯XAML中,管理这些语法用法的唯一规则如下:
满足这些条件使您可以使用相应的语法,无论后备依赖项属性是注册为常规还是附加.
现在提到的错误观念是由于绝大多数教程(连同Visual Studio代码片段)指示您将CLR属性用于常规依赖项属性,以及获取/设置附加属性的访问器.但是没有什么可以阻止你同时使用它们,允许你使用你喜欢的任何语法.
小智 5
附加属性基本上用于容器元素.就像你有一个网格并且你有grid.row现在这被认为是一个grid元素的附加属性.所以你可以在texbox,button等中使用这个属性来设置它放在网格中.
依赖属性就像属性基本上属于其他类,并在其他类中使用.例如:像这里有一个矩形高度和宽度是矩形的常规属性,但left和top是依赖属性,因为它属于Canvass类.
归档时间: |
|
查看次数: |
31400 次 |
最近记录: |