C# Silverlight中附加和非附加依赖属性之间的差异
好的,斯塔克尔斯,我在这个问题上花了好几个小时,我想知道是否有人有明确的答案。C# Silverlight中附加和非附加依赖属性之间的差异,c#,silverlight,dependency-properties,attached-properties,C#,Silverlight,Dependency Properties,Attached Properties,好的,斯塔克尔斯,我在这个问题上花了好几个小时,我想知道是否有人有明确的答案。 就我所做的所有研究而言,我在Silverlight中找不到.Register和.RegisterAttached之间的任何区别。现在,在你开始告诉我.RegisterAttached用于将DP附加到另一个类之前,请尝试使用DependencyProperty.Register()实现附加的依赖属性。我没有发现任何差异,因此我不知道差异是什么。 此外,在我的具体案例中,我试图扩展Grid类的功能,并希望为它提供一些额外
就我所做的所有研究而言,我在Silverlight中找不到
.Register
和.RegisterAttached
之间的任何区别。现在,在你开始告诉我.RegisterAttached
用于将DP附加到另一个类之前,请尝试使用DependencyProperty.Register()
实现附加的依赖属性。我没有发现任何差异,因此我不知道差异是什么。此外,在我的具体案例中,我试图扩展Grid类的功能,并希望为它提供一些额外的属性。因此,我尝试将
typeof(Grid)
和typeof(FluidLayoutManager)
(实现类)列为ownerType参数,这似乎也没有什么区别。。。(我相信当我从同一名称空间传递两个自定义类时,它确实会有所不同。但是,当传递Microsoft定义的类与自定义类时,我总是将其作为自定义类的DP显示在XAML中。)我坐在这里挠头,想知道是否有什么区别,或者微软是不是又跟我开玩笑了。如果你向RegisterAttached注册,它将成为任何DependencyObject存储中的一个全局属性,也就是说,您可以在任何依赖项对象上设置值 如果在调用Get/Setvalue时使用Register,将检查调用是否为可强制转换为注册类型的对象
行为类似RegisterAttached的属性的一个示例是Grid.Row和Grid.Column。就实现而言,它们可能没有太大的不同,但它们在操作上是不同的,即它们的作用和用途不同 Simple
Register
用于简单的依赖属性,您通常将其用于绑定和验证,因此它们是普通的CLR属性,具有一些额外的魔力,有助于WPF
RegisterAttached
通常用于希望公开可在子类中访问和设置的属性的情况,如DockPanel
,其中控件的子级使用Dock.Left
或Dock.Right
告诉父级它们要放置的位置。因此,它们是一种特殊的依赖属性,可以在子控件中访问(这与简单的寄存器
属性不同),并且它们(在DockPanel
的情况下)帮助父控件显示子控件
简言之,Register
用于注册在同一类中使用的依赖属性
,而RegisterAttached
用于注册称为附加属性
的特殊依赖属性,这些属性由定义它的类以外的类使用和访问
这是对附加属性的一个很好的解释,以及通过简单的DP无法实现的功能。鉴于评论中的讨论,我将尝试用简单的英语进行说明: 附加的依赖项属性和依赖项属性(以及.Register和.RegisterAttached)之间的主要区别在于,RegisterAttached允许将值分配给任何依赖项对象,而Register只允许将其附加到作为ownerType参数传递的类 如前所述(在注释线程的深处),您的示例使用的是唯一允许的类型(即CustomControl),并且没有向您显示可以将附加的版本分配给任何依赖项对象 e、 g.您可以使用附加的依赖项属性(但不是普通的DP)执行此操作:
我能找到的ADP的最佳参考是:
我们使用ADP作为本地化系统的基础,因此在加载过程中可以将翻译寄生到对象上,而不是使用非常长的绑定。用DPs不能这么做
更新:
我还想澄清,父限制适用于基于XAML的属性使用。从代码来看,父级限制显然不适用。认为“RegisterAttached允许将值分配给任何依赖项对象,而Register只允许将其附加到作为ownerType参数传递的类”是错误的。以下是一个在注册处注册的附属财产的完美工作示例:
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之间的唯一区别是,寄存器抛出了大部分提供的元数据,并且只为注册类的实例保留元数据(通过OverrideMetadata)。这意味着元数据中通常指定的继承和各种更新通知等属性不适用于使用Register注册并附加到其他类型(注册类型除外)对象的属性。所以Register实际上是RegisterAttached的精简版本。这可能是出于性能原因
在Haris Hasan对其答案的评论中的链接中,如果将RegisterAttached更改为Register,按钮将停止移动(因为该属性不再为按钮类型提供AffectsParentArrange元数据),但当您调整窗口大小时,按钮仍会在其新位置重新绘制。但如果在调用InitializeComponent()后向按钮类型添加相同的元数据:
然后一切都像调用RegisterAttached一样重新运行。那么RegisterAttached中使用的“ownerType”到底是什么呢?这个问题困扰了我好几年,所以我最后仔细查看了WindowsBase中的4.6.1代码 对于任何
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));
}
}
RadialPanel.AngleProperty.OverrideMetadata(
typeof(Button),
new FrameworkPropertyMetadata(
0.0, FrameworkPropertyMetadataOptions.AffectsParentArrange));
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);
}