好的Stackers,我在这个问题上花了好几个小时,我想知道是否有人有明确的答案。
对于我所做的所有研究,我在 Silverlight 中找不到.Register
和.RegisterAttached
之间的任何差异。现在,在你跳枪并告诉我.RegisterAttached
用于将DP附加到另一个类之前,尝试使用DependencyProperty.Register()
实现附加依赖属性。我发现没有一个区别,所以我不知道有什么不同。
此外,在我的具体情况下,我试图扩展Grid类的功能,并希望给它一些额外的属性。因此,我尝试将typeof(Grid)
和typeof(FluidLayoutManager)
(实现类)的列表作为ownerType参数传递,它似乎也没什么区别......(我相信它确实有所作为当我从同一名称空间传递两个自定义类时。但是当传递Microsoft定义的类与自定义类时,我总是将它作为自定义类的DP显示在XAML中。)
关于这个主题的任何澄清将非常感激,因为我坐在这里挠挠脑袋,想知道是否有任何差异,或者微软是否只是再次与我联系。
答案 0 :(得分:9)
鉴于讨论中的讨论流程,我将尝试用简单的英语进行讨论:
附加依赖项属性和依赖项属性之间的主要区别(因此介于.Register和.RegisterAttached之间)是RegisterAttached允许将值分配给任何依赖项对象,而Register只允许将它附加到作为传递的类传递 ownerType 参数。
正如Haris Hasan提到的那样(在评论主题的深处),您的示例使用了唯一允许的类型(即CustomControl),并没有向您显示可以将附加版本分配给任何依赖项对象。
e.g。您可以使用附加依赖属性(但不是普通DP)执行此操作:
<Grid local:AttacherClass.ADP1="1" x:Name="LayoutRoot" Background="White">
</Grid>
我能找到的ADP的最佳参考是:http://msdn.microsoft.com/en-us/library/ms749011.aspx
我们使用ADP作为本地化系统的基础,因此翻译可以在加载期间寄生在对象上,而不是使用可怕的长绑定。 DP无法做到这一点
我还想澄清一下,父限制适用于基于XAML的属性使用。从代码来看,父限制显然不适用。
答案 1 :(得分:6)
认为“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)。这意味着通常在元数据中指定的继承和各种更新通知等属性不适用于使用Register注册并附加到其他类型的对象(注册类型除外)的属性。所以Register实际上是RegisterAttached的精简版本。出于性能原因,它可能就是这样做的。
在Haris Hasan在他的回答评论中链接的example中,如果你将RegisterAttached更改为Register,按钮会停止移动(因为该属性不再为Button类型提供AffectsParentArrange元数据)但是它们仍然被重绘在调整窗口大小时,在新位置。但是,如果在调用InitializeComponent()之后向Button类型添加相同的元数据:
RadialPanel.AngleProperty.OverrideMetadata(
typeof(Button),
new FrameworkPropertyMetadata(
0.0, FrameworkPropertyMetadataOptions.AffectsParentArrange));
然后一切都再次起作用,就像调用RegisterAttached一样。
答案 2 :(得分:5)
就实施而言,它们可能没有太大的不同,但它们在行动方面存在差异,即它们的作用与用途不同。
简单Register
用于简单的依赖项属性,通常用于绑定和验证,因此它们是普通的CLR属性,带有一些额外的魔法,有助于WPF
RegisterAttached
通常用于您希望公开可以在子类中访问和设置的属性,例如DockPanel
,其中控制的子级使用{{1}告诉父级他们想要放置的位置}或Dock.Left
。所以它们是一种特殊的依赖属性,可以在子控件中访问(简单的Dock.Right
属性不是这种情况)并且它们(在Register
的情况下)帮助父控件显示子节点< / p>
简而言之,一个cay说DockPanel
用于注册Register
,它们在同一个类中使用,而dependency properties
用于注册名为RegisterAttached
的特殊依赖项属性并使用它们并由除定义它之外的类访问
This是附加属性的一个很好的解释,通过简单的DP
无法实现答案 3 :(得分:2)
如果您使用RegisterAttached注册,它将变为全局作为任何DependencyObject的存储中的属性,即您可以在任何依赖对象上设置SetValue
如果在调用Get / Setvalue时使用Register,则会检查调用是否是可转换为注册类型的对象。
与RegisterAttached类似的属性示例是Grid.Row和Grid.Column。
答案 4 :(得分:1)
究竟什么是'ownerType'用于RegisterAttached?这个问题一直困扰着我几年,所以我终于仔细研究了WindowsBase中的4.6.1代码。 / p>
对于任何DependencyProperty
,附加或其他,它最终归结为什么类型的PropertyDescriptor
WPF获得后期绑定XAML访问,并且直到第一次才确定(在每种类型/属性配对的基础上)尝试这种访问。这种推迟是必要的,因为PropertyDescriptor
封装了绑定到特定类型的属性,而附加属性的点是为了避免这种情况。
当XAML访问发生时,({1}}与Register(...)
的区别已经失去了(运行)时间的迷雾。正如其他人在此页面上所指出的,“DependencyProperty”本身并不编码附加与非变种之间的区别。假设每个DP都符合使用条件,仅限于在运行时可以计算的内容。
例如,下面的.NET代码似乎依赖不在'tOwner'类型上找到匹配的实例属性作为允许附加访问的第一个要求。为了确认这个诊断,它然后检查'tOwner'是否公开了一种静态访问方法。这是一个模糊的检查,因为它不验证方法签名。这些签名仅对XAML访问有意义;附加属性的所有实际运行时目标必须是RegisterAttached(...)
s,WPF尽可能通过DependencyObject
访问。 (据报道,VS Designer确实使用了静态访问器,如果没有它们,你的XAML将无法编译)
相关的.NET代码是静态函数DependencyObject.GetValue/SetValue
,此处显示我自己的评论(摘要如下):
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
时,唯一的'ownerType'用于标识定义适当的静态Get / Set访问器的类型。这些访问器中至少有一个必须存在于'ownerType'上,否则XAML附加访问将无法编译或无提示失败。虽然RegisterAttached在这种情况下不会失败,而是成功返回一个已失效的DP。对于仅供附加使用的DP,'tOwner'不必从DependencyObject派生。您可以使用任何常规.NET类,静态或非静态,实际上甚至可以是结构!