本文大多内容摘自, 更详细的内容请去看原文,我只是写出我感兴趣的地方:
http://www.cnblogs.com/KnightsWarrior/archive/2010/08/27/1809739.html
依赖属性 (Dependency Property)
大家都知道WPF带来了很多新的特性,它的一大亮点是引入了一种新的属性机制——依赖属性。依赖属性基本应用在了WPF的所有需要设置属性的元素。依赖属性根据多个提供对象来决定它的值(可以是动画、父类元素、绑定、样式和模板等),同时这个值也能及时响应变化。所以WPF拥有了依赖属性后,代码写起来就比较得心应手,功能实现上也变得非常容易了。如果没有依赖属性,我们将不得不编写大量的代码。
依赖属性相比普通属性的优点
1、 新功能的引入:加入了属性变化通知,限制、验证等等功能,这样就可以使我们更方便的实现我们的应用,同时也使代码量大大减少了,许多之前不可能的功能都可以轻松的实现了。
2、 节约内存:在WinForm等项目开发中,你会发现UI控件的属性通常都是赋予的初始值,为每一个属性存储一个字段将是对内存的巨大浪费。WPF依赖属性解决了这个问题,它内部使用高效的稀疏存储系统,仅仅存储改变了的属性,即默认值在依赖属性中只存储一次。
3、 支持多个提供对象:我们可以通过多种方式来设置依赖属性的值。同时其内部可以储存多个值,配合Expression、Style、Animation等可以给我们带来很强的开发体验。
在什么时候适合试用依赖属性
1. 希望属性支持动态资源引用
2. 希望在样式中试用的属性
3. 希望属性支持动画
4. 希望属性支持数据绑定
5. 希望属性支持属性值继承
6. 希望属性发生改变时触发一些列的行为
7. 希望属性有自己的元数据
8. 希望属性得到WPF设计器的支持,如在WPF属性窗口中直接修改其直。
如何定义依赖属性
实现一个依赖属性必须满足一下条件:
1. 让该类继承自DependencyObject类, 只用DependencyObject类才可以注册和拥有依赖属性。
2. 在该类中定义一个public static readonly成员变量,类型为DependecyProperty, 如:“public static readonly DependecyProperty IsDefaultProperty;”。
3. 将该依赖属性名命名为“属性名+Propery”, 如Button的IsDefault属性,必须命名为”IsDefaultProperty”.
4. 调用DependecyProperty的注册方法(Register及RegisterReadOnly)在WPF属性系统中注册该依赖属性。
5. 为该依赖属性实现一个.Net属性包装器。
6. public class SampleDPClass : DependencyObject
{
//声明一个静态只读的DependencyProperty字段
public static readonly DependencyProperty SampleProperty;
static SampleDPClass()
{
//注册我们定义的依赖属性Sample
SampleProperty = DependencyProperty.Register("Sample", typeof(string), typeof(SampleDPClass),
new PropertyMetadata("Knights Warrior!", OnValueChanged));
}
private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
//当值改变时,我们可以在此做一些逻辑处理
}
//属性包装器,通过它来读取和设置我们刚才注册的依赖属性
public string Sample
{
get { return (string)GetValue(SampleProperty); }
set { SetValue(SampleProperty, value); }
}
}
总结:我们一般.NET属性是直接对类的一个私有字段进行封装,所以读取值的时候,也就是直接读取这个字段;而依赖属性则是通过调用继承自DependencyObject的GetValue()和SetValue来进行操作,它实际存储在DependencyProperty的一个IDictionary的键-值配对字典中,所以一条记录中的键(Key)就是该属性的HashCode值,而值(Value)则是我们注册的DependencyProperty。
依赖属性的优先级
由于这个流程图偏理想化,很多时候我们会遇到各种各样的问题,这里也不可能一句话、两句话就能够把它彻底说清楚,所以我们就不过多纠缠。等遇到问题之后要仔细分析,在找到原因之后也要不断总结、举一反三,只有这样才能逐渐提高
依赖属性的元数据
前面我们看到一个依赖属性的注册最全的形式是下面这样子的:
public static DependencyProperty Register(string name,
Type propertyType,
Type ownerType,
PropertyMetadata typeMetadata,
ValidateValueCallback validateValueCallback);
第一个参数是该依赖属性的名字,第二个参数是依赖属性的类型,第三个参数是该依赖属性的所有者的类型,第五个参数就是一个验证值的回调委托,那么最使我们感兴趣的还是这个可爱的 PropertyMetadata ,也就是我们接下来要讲的元数据。 提到WPF属性元数据,大家可能第一想到的是刚才的PropertyMetadata,那么这个类到底是怎样的呢?我们应该怎样使用它呢?首先我们看它的构造函数(我们选参数最多的来讲):
public PropertyMetadata(object defaultValue,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback);
其中的第一个参数是默认值,最后两个分别是PropertyChanged(变化通知)以及Coerce(强制)的两个委托变量,我们在实例化的时候,只需要把这两个委托变量关联到具体的方法上即可。
事实上,除了PropertyMetadata以外,常见的还有FrameworkPropertyMetadata,UIPropertyMetadata。他们的继承关系是F->U->P。其中以FrameworkPropertyMetadata参数最多,亦最为复杂。
FrameworkPropertyMetadata的构造函数提供了很多重载,我们挑选最为复杂的重载来看它到底有哪些参数以及提供了哪些功能:
public FrameworkPropertyMetadata(object defaultValue,
FrameworkPropertyMetadataOptions flags,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback,
bool isAnimationProhibited,
UpdateSourceTrigger defaultUpdateSourceTrigger);
其中第一个参数是默认值,最后两个参数分别是是否允许动画,以及绑定时更新的策略(在Binding当中相信大家并不陌生),这个不详细解释了。重点看一下里第三、四两个参数,两个 CallBack的委托。结合前面Register的时候提到的ValidateValueCallback共组成三大”金刚“,这三个Callback分别代表Validate(验证),PropertyChanged(变化通知)以及Coerce(强制)。当然,作为 Metadata,FrameworkPropertyMetadata只是储存了该依赖属性的策略信息,WPF属性系统会根据这些信息来提供功能并在适当的时机回调传入的delegate,所以最重要的还是我们定义的这些方法,通过他们传入委托才能起到真正的作用。
上面讲了元数据暴露给我们的构造函数,其实在其内部还提供了两个方法,这个在做自定义控件的时候,也很值得注意:
protected virtual void Merge(PropertyMetadata baseMetadata, DependencyProperty dp)
{
// 实现元数据继承之间的合并
}
protected virtual void OnApply(DependencyProperty dependencyProperty, Type targetType)
{
// 当元数据被这个属性应用,OnApply就会被触发,在此时元数据也将被密封起来。
}
详细的请去http://www.cnblogs.com/KnightsWarrior/archive/2010/08/27/1809739.html查看