Silverlight:DependencyProperty
Dependency Property (依赖属性) 是一个全新(陌生)但有无法回避的概念。
通过 CLR 属性可以支持样式设置、数据绑定、动画和默认值,而这些功能也可通过将其作为依赖项属性实现来获得。依赖项属性是通过调用DependencyProperty的Register方法向Silverlight 属性系统注册并由 DependencyProperty标示符字段标识的属性。依赖属性只能由DependencyObject类型使用,但DependencyObject在Silverlight类层次结构中的级别很高,因此,Silverlight中大多数可用于用户界面和演示的类都可能支持依赖项属性。
为什么会出现依赖属性?
在传统的属性(Property)中,通常我们读取或者赋值一个属性时,实际上是在对属性背后的某个私有成员进行读写。那么随着对象的属性越来越多,再加上从对象派生出去的子对象,子对象再派生出孙对象……最终的对象运行示例中会有大量的私有成员,而每个私有成员都要分配内存,占用一定的资源。再反过来想想,通常我们在使用一个控件或对象时,往往只用到某几个属性,大部分属性都采用的是默认值(或者可以理解没有用到),这对于Silverlight和WPF来说无疑是一种极大的性能损耗。在此背景下DependencyProperty就出现了。我们再回想一下静态的方法或成员,静态的方法和成员的调用不依赖于实例,它是class级别的,不管这个类有多少个实例,静态成员在内存中只占一份,这正是我们所需要的。
什么时候实现依赖属性?
属性成为依赖项属性并不始终必要或适当,具体取决于您的需要。有时,使用私有字段支持属性的典型方法便能满足要求。但是,只要您希望属性支持以下一种或多种 Silverlight 属性系统功能,就应将您的属性作为依赖项属性实现:
(1) 您希望可在样式中设置此属性。
(2) 您希望此属性支持数据绑定。
(3) 您希望此属性支持经过动画处理的值。
(4) 您希望 Silverlight 属性系统在属性系统本身、环境或用户执行的操作或者读取并使用样式而更改了属性以前的值时进行报告。您的属性可以指定在每次属性系统确定属性值已被明确更改时将调用的回调方法。
依赖属性的大致原理?
所有具备依赖属性的对象,都是继承自DependencyObject,DependencyObject中有一个“字典“存储区用来存放依赖属性,而且都是用static方式读取的。所以你现在应该想明白了,为什么在托管堆代码中不能直接用btn.Left=xxx来赋值,而必须使用btn.SetValue(Canvas.Left ,xxx)来处理。因为static成员是实例无法调用的。
依赖属性的优点:
(1) 有效降低内存消耗
(2) 直接继承上级的属性值(这里也解释了为什么上级控件对下级控件的自动布局,因为下级控件自动继承了上级控件的相关属性值)
(3) 自动实现了变化通知(DependencyProperty有内置的Change Notification回调接口)
依赖属性的读取策略:
上图描述了 GetValue 和 SetValue 的内部读取策略。
依赖属性示例:
public class Book : DependencyObject
{
public string BookName
{
get { return (string)GetValue(BookNameProperty); }
set { SetValue(BookNameProperty, value); }
}
public static readonly DependencyProperty BookNameProperty =
DependencyProperty.Register("BookName", typeof(string), typeof(Book), null);
}