Silverlight 中附加依赖属性和非附加依赖属性之间的差异
好吧,Stackers,我在这个问题上花了几个小时,我想知道是否有人有明确的答案。
对于我所做的所有研究,我在 Silverlight 中找不到 .Register
和 .RegisterAttached
之间的任何区别。现在,在您贸然告诉我 .RegisterAttached
用于将 DP 附加到另一个类之前,请尝试使用 DependencyProperty.Register()
实现附加依赖属性。我没有发现任何差异,所以我不知道差异是什么。
此外,在我的具体情况下,我试图扩展 Grid 类的功能,并希望为其提供一些额外的属性。因此,我尝试列出将 typeof(Grid)
和 typeof(FluidLayoutManager)
(实现类)作为ownerType 参数传递,并且它似乎也没有什么作用区别...(我相信当我从同一命名空间传递两个自定义类时,它确实会产生影响。但是,当传递 Microsoft 定义的类与自定义类时,我总是将其作为 DP 的 DP 显示在 XAML 中自定义类。)
如果我对这个话题有任何澄清,我将不胜感激,因为我坐在这里挠头,想知道是否有任何区别,或者微软是否再次与我搞砸。
Okay Stackers, I've spent a good couple of hours on this question, and I want to know if anybody has a definitive answer.
For all the research I've done, I can't find ANY difference between .Register
and .RegisterAttached
in Silverlight. Now, before you jump the gun and tell me that .RegisterAttached
is used for attaching a DP to another class, try implementing an Attached Dependency Property using DependencyProperty.Register()
. I have found not a single difference, and so I am at a loss as to what the difference is.
Furthermore, in my specific case, I'm attempting to extend the functionality of the Grid class, and want to give it some extra properties. As such, I've tried listing passing both typeof(Grid)
and typeof(FluidLayoutManager)
(the implementing class) as the ownerType parameter and it also seems to make very little difference... (I believe it does make a difference when I pass two custom classes from the same namespace. However when passing a Microsoft defined class vs. a custom class, I always have it showing up in the XAML as a DP of the custom class.)
Any clarification on this topic would be much appreciated, as I'm sitting here scratching my head, and wondering if there is any difference at all, or if Microsoft is just screwing with me once again.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
鉴于评论中的讨论,我将尝试用简单的英语进行此讨论:
附加依赖项属性和依赖项属性(以及 .Register 和 .RegisterAttached 之间)之间的主要区别是 RegisterAttached 允许将值分配给任何依赖项对象而 Register 只允许它附加到作为 ownerType 参数传递的类。
正如 Haris Hasan 提到的(在评论线程深处),您的示例使用的是唯一允许的类型(即 CustomControl)并且不会向您显示附加版本可以分配给任何依赖项对象。
例如,您可以使用附加依赖属性(但不是普通的 DP)来执行此操作:
我能找到的 ADP 的最佳参考是这个:http://msdn.microsoft.com/en-us/library/ms749011.aspx
我们使用ADP 作为本地化系统的基础,因此翻译可以在加载期间寄生到对象上,而不是使用可怕的长绑定。无法使用 DP 做到这一点
更新:
我还想澄清一下,父级限制适用于基于 XAML 的属性使用。从代码来看,父级限制显然不适用。
Given the discussions flowing in comments I will try to do this one in plain English:
The main difference between Attached Dependency Properties and Dependency Properties (and therefore between .Register and .RegisterAttached) is that RegisterAttached allows the value to be assigned to any dependency object whereas Register only allows it to be attached to the class passed as the ownerType parameter.
As Haris Hasan mentions (deep in the comment thread), your example is using the only type allowed (i.e. CustomControl) and does not show you that the Attached version can be assigned to ANY dependency object.
e.g. you can do this with your Attached Dependency Property (but not a plain DP):
The best reference for ADPs I can find is this one: http://msdn.microsoft.com/en-us/library/ms749011.aspx
We used ADPs as the basis of a localisation system, so that translations could be parasited onto objects during load rather than using horrendously long bindings. Couldn't do that with DPs
Update:
I would also like to clarify that the parent limitation applies to XAML based use of the attribute. From code the parent limitation apparently does not apply.
相信“RegisterAttached 允许将值分配给任何依赖对象,而 Register 只允许将其附加到作为ownerType 参数传递的类”是错误的。下面是一个使用 Register 注册的附加属性的完美工作示例:
Reflector 表明 Register 和 RegisterAttached 之间的唯一区别是 Register 会丢弃大部分提供的元数据,并且仅为注册类的实例保留它(通过 OverrideMetadata)。这意味着通常在元数据中指定的继承和各种更新通知等属性不适用于通过 Register 注册并附加到其他类型(注册类型除外)对象的属性。所以Register实际上是RegisterAttached的精简版本。这样做可能是出于性能原因。
在 Haris Hasan 链接的示例中对他的答案的评论,如果您将 RegisterAttached 更改为 Register,按钮将停止移动(因为该属性不再为 Button 类型提供 AffectsParentArrange 元数据),但当您调整窗口大小。但是,如果在调用 InitializeComponent() 之后将相同的元数据添加到 Button 类型:
那么一切都会再次正常工作,就像调用 RegisterAttached 一样。
It is wrong to believe that "RegisterAttached allows the value to be assigned to any dependency object whereas Register only allows it to be attached to the class passed as the ownerType parameter". Here is a perfectly working example of an attached property registered with Register:
Reflector shows that the only difference between Register and RegisterAttached is that the Register throws out much of the supplied metadata and only preserves it for the instances of registering class (via OverrideMetadata). It means that attributes such as Inherits and various update notifications usually specified in the metadata do not work on properties registered with Register and attached to objects of other types (other than the registering type). So Register is actually a stripped down version of RegisterAttached. It was probably made this way for performance reasons.
In the example linked by Haris Hasan in the comments to his answer, if you change RegisterAttached to Register, the buttons stop moving (because the property no longer provides AffectsParentArrange metadata for Button type) but they are nevertheless redrawn in their new locations when you resize the window. But if you add the same metadata to the Button type after a call to InitializeComponent():
then everything works again as if RegisterAttached was called.
就实施而言,它们可能没有太大不同,但它们在操作上有所不同,即它们的作用和用途不同。
Simple
Register
用于简单的依赖属性,通常用于绑定和验证,因此它们是普通的 CLR 属性,并具有一些额外的魔力,有助于 WPFRegisterAttached
通常用于以下位置您想要公开一个可以在子类中访问和设置的属性,例如DockPanel
,其中控件的子级使用Dock.Left
告诉父级它们想要放置的位置或Dock.Right
。因此,它们是一种特殊的依赖属性,可以在子控件中访问(这不是简单的Register
属性的情况),并且它们(在DockPanel
的情况下)有帮助父控件显示子项简而言之,
Register
用于注册在同一类中使用的依赖属性
,而RegisterAttached
用于注册特殊属性名为attached 的依赖属性属性
,并且它们由定义它的类以外的类使用和访问这很好地解释了附加属性以及通过简单 DP 无法实现的内容
They might not be much different as far as implementation is concerned but they are difference in actions i.e. they are different in what they do and are used for.
Simple
Register
is used for simple dependency properties which you usually are used for bindings and validations so they are normal CLR properties with some additional magic which helps in WPFRegisterAttached
is normally used where you want to expose a property that can be accessed and set in the child class likeDockPanel
where children of control tells parent where they want to be placed usingDock.Left
orDock.Right
. So they are kind of special dependency properties which can be accessed in the child controls (which is not the case with simpleRegister
properties) and they(in case ofDockPanel
) helps parent control in displaying childrenIn short one cay say
Register
is used registeringdependency properties
which are used in same class whileRegisterAttached
is used for registering special dependency properties calledattached properties
and they are used and accessed by classes other than one which defined itThis is a good explanation of Attached Properties and what cannot be achieved through simple DP
如果您使用 RegisterAttached 进行注册,则它会成为任何 DependencyObject 存储中的全局属性,即您可以在任何 DependencyObject 上 SetValue
如果您在调用 Get/Setvalue 时使用 Register,则会检查该调用是否来自一个对象:可转换为注册类型。
行为类似于 RegisterAttached 的属性的示例是 Grid.Row 和 Grid.Column。
If you register with RegisterAttached, it becomes global as a property in the store of any DependencyObject, i.e. you could SetValue on any Dependency Object
If you use Register when Get/Setvalue are called there will be a check that the call is prom an object that is castable to the registering type.
An Example of a property that behaves like RegisterAttached is Grid.Row and Grid.Column.
那么 RegisterAttached 中的“ownerType”到底是用来做什么的? 这个问题已经困扰了我好几年了,所以我最终仔细研究了 WindowsBase 中的 4.6.1 代码。
对于任何
DependencyProperty
(无论是附加的还是其他方式),它最终归结为 WPF 为后期绑定 XAML 访问获取什么类型的PropertyDescriptor
,并且直到第一次(基于每个类型/属性配对)尝试此类访问。这种延迟是必要的,因为PropertyDescriptor
封装了绑定到特定类型的属性,而附加属性的目的就是为了避免这种情况。当 XAML 访问发生时,
Register(...)
与RegisterAttached(...)
的区别已经消失在(运行)时间的迷雾中。正如其他人在此页面上指出的那样,“DependencyProperty”本身并不编码附加与非品种之间的区别。假设每个 DP 都适合任一用途,仅取决于运行时可以计算出的内容。例如,下面的 .NET 代码似乎依赖于不在“tOwner”类型上查找匹配的实例属性作为允许附加访问的第一个要求。为了确认这一诊断,它会检查“tOwner”是否公开了其中一种静态访问方法。这是一个模糊的检查,因为它不验证方法签名。这些签名仅对 XAML 访问有意义;附加属性的所有实际运行时目标都必须是
DependencyObject
,WPF 只要有可能就通过DependencyObject.GetValue/SetValue
访问它。 (据报道,VS 设计器确实使用静态访问器,如果没有它们,您的 XAML 将无法编译)相关的 .NET 代码是静态函数
DependencyPropertyDescriptor.FromProperty
,此处显示了我自己的注释(摘要如下) ):摘要:当调用
RegisterAttached
创建附加的DependencyProperty
时,“ownerType”的唯一用途是识别定义适当的类型。静态获取/设置访问器。 “ownerType”上必须至少存在这些访问器之一,否则 XAML 附加访问将无法编译或静默失败。尽管 RegisterAttached 在这种情况下不会失败,而是成功返回了失效的 DP。对于仅用于附加使用的 DP,“tOwner”不必从 DependencyObject 派生。您可以使用任何常规 .NET 类(静态或非静态),实际上甚至可以是结构!So exactly what is 'ownerType' used for in RegisterAttached? This issue has been nagging at me for a few years, so I finally took a closer look at 4.6.1 code in WindowsBase.
For any
DependencyProperty
, attached or otherwise, what it eventually comes down to is what type ofPropertyDescriptor
WPF obtains for late-bound XAML access, and this isn't determined until the first time (on a per type/property pairing basis) such access is attempted. This deferral is necessary becausePropertyDescriptor
encapsulates a property bound to a specific type, whereas the point of attached properties is to avoid exactly this.By the time XAML access occurs, the
Register(...)
versusRegisterAttached(...)
distinction has been lost to the mists of (run)time. As others have noted on this page, 'DependencyProperty' itself doesn't encode a distinction between an attached vs. non- variety. Every DP is assumed to be eligible for either usage, subject only to what can be figured out at runtime.For example, the .NET code below seems to rely on not finding a matching instance property on the 'tOwner' type as the first requirement for allowing attached access. To confirm this diagnosis, it then checks whether 'tOwner' exposes one of the static access methods. This is a vague check insofar as it doesn't verify the method signatures. Those signatures only matter for XAML access; all actual runtime targets for the attached property must be
DependencyObject
s, which WPF accesses throughDependencyObject.GetValue/SetValue
whenever possible. (The VS Designer reportedly does use the static accessors, and your XAML won't compile without them)The relevant .NET code is the static function
DependencyPropertyDescriptor.FromProperty
, shown here with my own comments (summary below):Summary: When calling
RegisterAttached
to create an attachedDependencyProperty
, the only thing 'ownerType' is used for is to identify a type which defines appropriate static Get/Set accessors. At least one of those accessors must exist on 'ownerType' or XAML attached access will not compile or silently fail. Although RegisterAttached does not fail in this case, and instead successfully returns a defunct DP. For DPs intended for attached use only, 'tOwner' doesn't have to derive from DependencyObject. You can use any regular .NET class, static or non-static, and in fact can even be a struct!