Silverlight中附加和非附加依赖属性的区别
本文关键字:属性 区别 依赖 Silverlight | 更新日期: 2023-09-27 18:03:46
好了,我花了好几个小时在这个问题上,我想知道是否有人有一个明确的答案。
对于我所做的所有研究,我在Silverlight中找不到.Register
和.RegisterAttached
之间的任何差异。现在,在您跳枪并告诉我.RegisterAttached
用于将DP附加到另一个类之前,请尝试使用DependencyProperty.Register()
实现附加依赖属性。我没有发现任何不同,所以我不知道有什么不同。
此外,在我的特定情况下,我试图扩展Grid类的功能,并希望给它一些额外的属性。因此,我试着将typeof(Grid)
和typeof(FluidLayoutManager)
(实现类)作为ownerType参数传递给清单,它似乎也没有什么区别……(我相信当我从同一个名称空间传递两个自定义类时确实会产生差异。然而,当传递微软定义的类与自定义类时,我总是让它在XAML中显示为自定义类的DP。
任何关于这个话题的澄清将是非常感激的,因为我坐在这里挠头,想知道是否有任何不同,或者微软只是再一次欺骗我。
考虑到评论中的讨论,我将尝试用简单的英语来做这个:
附属依赖属性和依赖属性之间的主要区别(因此在.Register和.RegisterAttached之间)是,RegisterAttached允许将值分配给任何依赖对象,而Register只允许将其附加到作为ownerType参数传递的类。
正如Haris Hasan所提到的(在评论线程的深处),你的例子使用了唯一允许的类型(即CustomControl),并没有告诉你附件版本可以分配给任何依赖对象。
。你可以通过附加依赖属性(但不是普通的DP)来做到这一点:
<Grid local:AttacherClass.ADP1="1" x:Name="LayoutRoot" Background="White">
</Grid>
我能找到的adp的最佳参考是这个:http://msdn.microsoft.com/en-us/library/ms749011.aspx
我们使用adp作为本地化系统的基础,这样翻译可以在加载期间寄生到对象上,而不是使用可怕的长绑定。而DPs就不能这样
更新:
我还想澄清一下,父限制适用于基于XAML的属性使用。从代码中,父限制显然不适用。
认为"RegisterAttached允许将值分配给任何依赖对象,而Register只允许将其附加到作为ownerType参数传递的类"是错误的。下面是一个在Register中注册的附加属性的完美工作示例:
class FooPropertyDeclaringType
{
public static readonly DependencyProperty FooProperty =
DependencyProperty.Register("Foo", typeof(int), typeof(FooPropertyDeclaringType));
}
class SomeUnrelatedType : DependencyObject { }
class Program
{
static void Main()
{
var obj = new SomeUnrelatedType();
obj.SetValue(FooPropertyDeclaringType.FooProperty, 10);
Debug.Assert(10 == (int)obj.GetValue(FooPropertyDeclaringType.FooProperty));
}
}
Reflector显示Register和RegisterAttached之间的唯一区别是Register抛出大部分提供的元数据,并且仅为注册类的实例保留它(通过OverrideMetadata)。这意味着通常在元数据中指定的属性(如Inherits)和各种更新通知不适用于在Register中注册的属性和附加到其他类型对象(除了注册类型)的属性。Register实际上是RegisterAttached的简化版本。这样做可能是出于性能方面的考虑。
在哈里斯·哈桑在评论他的回答链接的例子中,如果你改变RegisterAttached到Register,按钮停止移动(因为属性不再为按钮类型提供AffectsParentArrange元数据),但是当你调整窗口大小时,它们仍然在新的位置重新绘制。但是,如果您在调用InitializeComponent()之后向Button类型添加相同的元数据:
RadialPanel.AngleProperty.OverrideMetadata(
typeof(Button),
new FrameworkPropertyMetadata(
0.0, FrameworkPropertyMetadataOptions.AffectsParentArrange));
然后一切又工作了,如果RegisterAttached被调用
就实现而言,它们可能没有太大的不同,但它们在动作上是不同的,即它们在做什么和用于什么方面是不同的。
Simple Register
用于简单的依赖属性,这些属性通常用于绑定和验证,因此它们是普通的CLR属性,带有一些额外的魔法,可以帮助WPF
RegisterAttached
通常用于您想要公开可以在子类(如DockPanel
)中访问和设置的属性,其中control的子类告诉父类他们想要使用Dock.Left
或Dock.Right
放置的位置。所以它们是一种特殊的依赖属性可以在子控件中访问(简单的Register
属性不是这样的)它们(在DockPanel
的情况下)帮助父控件显示子
简而言之,可以说Register
用于注册dependency properties
,它们在同一个类中使用而RegisterAttached
用于注册称为attached properties
的特殊依赖属性它们由定义它的类以外的类使用和访问
这是附加属性的一个很好的解释,什么不能通过简单的DP
如果你注册了RegisterAttached,它将成为任何DependencyObject存储中的全局属性,即你可以在任何依赖对象上SetValue
如果在调用Get/Setvalue时使用Register,将会检查调用是否为可转换为注册类型的对象。
一个类似RegisterAttached属性的例子是Grid。行,网格,列。
那么究竟什么是'ownerType'用于RegisterAttached?这个问题已经困扰我好几年了,所以我终于仔细研究了一下WindowsBase的4.6.1代码。
对于任何DependencyProperty
,无论是附加的还是其他的,它最终归结为WPF为后期绑定的XAML访问获得什么类型的PropertyDescriptor
,直到第一次尝试这样的访问(基于每个类型/属性配对)才确定。这种延迟是必要的,因为PropertyDescriptor
封装了绑定到特定类型的属性,而附加属性的目的正是为了避免这种情况。
Register(...)
和RegisterAttached(...)
的区别已经消失在(运行)时间的迷雾中。正如其他人在本页所指出的,"DependencyProperty"本身并没有编码附加与非品种之间的区别。每个DP都被假定为符合任何一种用法,仅受运行时可以计算出的内容的限制。
例如,下面的。net代码似乎依赖于而不是在'tOwner'类型上找到匹配的实例属性作为允许附加访问的第一个要求。为了确认这个诊断,它然后检查'tOwner'是否暴露了一个静态访问方法。这是一种模糊的检查,因为它不验证方法签名。这些签名只对XAML访问有影响;附加属性的所有实际运行时目标必须是DependencyObject
s, WPF尽可能通过DependencyObject.GetValue/SetValue
访问它。(据报道VS设计器确实使用静态访问器,没有它们你的XAML将无法编译)
相关的。net代码是静态函数DependencyPropertyDescriptor.FromProperty
,在这里显示了我自己的注释(总结如下):
internal static DependencyPropertyDescriptor FromProperty(DependencyProperty dp, Type tOwner, Type tTarget, bool _)
{
/// 1. 'tOwner' must define a true CLR property, as obtained via reflection,
/// in order to obtain a normal (i.e. non-attached) DependencyProperty
if (tOwner.GetProperty(dp.Name) != null)
{
DependencyPropertyDescriptor dpd;
var dict = descriptor_cache;
lock (dict)
if (dict.TryGetValue(dp, out dpd))
return dpd;
dpd = new DependencyPropertyDescriptor(null, dp.Name, tTarget, dp, false);
lock (dict)
dict[dp] = dpd;
/// 2. Exiting here means that, if instance properties are defined on tOwner,
/// you will *never* get the attached property descriptor. Furthermore,
/// static Get/Set accessors, if any, will be ignored in favor of those instance
/// accessors, even when calling 'RegisterAttached'
return dpd;
}
/// 3. To obtain an attached DependencyProperty, 'tOwner' must define a public,
/// static 'get' or 'set' accessor (or both).
if ((tOwner.GetMethod("Get" + dp.Name) == null) && (tOwner.GetMethod("Set" + dp.Name) == null))
return null;
/// 4. If we are able to get a descriptor for the attached property, it is a
/// DependencyObjectPropertyDescriptor. This type and DependencyPropertyDescriptor
/// both derive directly from ComponentModel.PropertyDescriptor so they share
/// no 'is-a' relation.
var dopd = DependencyObjectProvider.GetAttachedPropertyDescriptor(dp, tTarget);
/// 5. Note: If the this line returns null, FromProperty isn't called below (new C# syntax)
/// 6. FromProperty() uses the distinction between descriptor types mentioned in (4.)
/// to configure 'IsAttached' on the returned DependencyProperty, so success here is
/// the only way attached property operations can succeed.
return dopd?.FromProperty(dopd);
}
总结:当调用RegisterAttached
来创建一个附加的DependencyProperty
时,'ownerType'唯一的作用是识别一个类型,该类型定义了适当的静态Get/Set访问器。这些访问器中至少有一个必须存在于'ownerType'上,否则XAML附加访问将无法编译或静默失败。尽管RegisterAttached在这种情况下没有失败,而是成功返回一个失效的DP。对于仅用于附加使用的dp, 'tOwner'不必派生自DependencyObject。您可以使用任何常规的。net类,静态或非静态,实际上甚至可以是一个结构体!