一 引入DependencyProperty


这个概念可以说是WPF核心中的核心了。在WPF的框架中随时都能见到它的身影。关于DependencyProperty能带来的诸多方便,很多介绍性的文章里都有,我这里就不介绍了,今天先从什么是DependencyProperty说起。

 
从属性开始属性

在CLR中有属性(Property)这个概念,它可以用来封装字段。

      这种属性应用的非常多,我们还可以在set或get方法中加入某些逻辑,确定读取或者设置属性的值的时候我们是不是需要某些其他的判断,一个经典的例子是在Age属性的set方法中加入对年龄范围的判断。这些就不多说了。




WPF中ProgressBar上的文本_wpf

private

  string  _myString;

WPF中ProgressBar上的文本_wpf


public   string  MyString

WPF中ProgressBar上的文本_wpf_03

WPF中ProgressBar上的文本_设计模式_04



WPF中ProgressBar上的文本_设计模式_05


{

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_06

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_07

         get

WPF中ProgressBar上的文本_设计模式_05

{return _myString;}

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_06

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_07

        set

WPF中ProgressBar上的文本_设计模式_05

{_myString=value;}

WPF中ProgressBar上的文本_.net_12

}

 

      但是WPF框架的编程经常和界面打交道,经常遇到的一个情况是某个属性的值的变化会影响到多个其他对象。比如当一个Button的改变大小超过了它的容器,他的容器应该自动调整大小。于是我们考虑在每个属性的set方法中触发一些事件,但很快我们发现现有的功能很难满足我们的需求,至少不能简洁漂亮的满足这些需求。
      实际上我们的需求更加复杂,WPF中的数据绑定,XAML语法等很多地方都和属性密切相关,我们迫切需要一种功能更加强大的属性。

      于是在WPF中,引入了一种特殊的属性,Dependency Property。这种属性和普通的属性最大不同在于,它的值的来源并不单一。对这种属性的取值和赋值都会能与其他对象有影响,因此能得到很大的灵活性。

这很抽象,也许很难懂。不明白不要紧,先接着看。一步步来,先看看DependencyProperty长什么样,从定义DependencyProperty开始:



WPF中ProgressBar上的文本_wpf

public  

static   readonly  DependencyProperty MyStringProperty  =  DependencyProperty.Register(

WPF中ProgressBar上的文本_wpf

             "

MyString " ,

WPF中ProgressBar上的文本_wpf

             typeof

( string ),

WPF中ProgressBar上的文本_wpf

             typeof

(ClassMyDependency),

WPF中ProgressBar上的文本_wpf

             new

 PropertyMetadata( " defaultValue " ,  new  PropertyChangedCallback(onMyStringPropertyChange)));

WPF中ProgressBar上的文本_wpf


 

一眼看上去很复杂,首先使用public static readonly的方式(其实就是设计模式里的单键 这是.net里的一种简单实现)定义了一个全局的DenpendencyProperty成员,这个成员的值通过DependencyProperty的Register方法获得,这个成员我们称做DependencyProperty标识。

我们传入了一些参数,分别表示属性名,属性类型,父元素(也就是包含属性的元素)类型,属性元数据(这些以后再详细介绍)。
要注意的是, 虽然我们定义的名称是MyStringProperty,但是属性的名称不是成员的名称,它由第一个参数指定.这个Property的后缀不是可选的,虽说不按照这个规则编译能通过,但是.net中很多地方都遵循了这种规则,这里我们了解这个规则并保证自己定义的DependecyProperty都遵循它就行了,以后会有更详细的解释.

实际上我们得到了一个属性的标识,这个数据是全局的且是唯一确定的,当需要访问属性的值时,只需要调用对象的GetValue()和SetValue()方法来访问()。语法是:

GetValue(property)
SetValue(property, value)

方法的调用者,不仅可以是定义DependencyProperty的对象,它可以是任何继承了DependencyObject的对象,换句话说,这个属性定义在了这里,但是它并不完全属于这个对象。这很不好理解,不过也正是DependencyProperty功能的强大之处之一,现在先不必深究这个。 
 
不过使用GetValue和SetValue方法给属性赋值让我们很不习惯,于是我们可以对这两个方法进行封装,在上面DependencyProperty的定义之后加上:

 

 

这在MSDN中称为”CLR封装(wrapper)”,这是可选的,不过经过封装之后,这样对于外界来说,DependencyProperty就和传统属性没有什么区别了,实现了完全的“向下兼容”。 

  虽然我们还不很清楚DependencyProperty到底可以用来做什么,但现在为止至少已经实现了传统属性的所有功能,注意到,我们并没有定义那个private的私有字段。实际上,.net自动为我们创建了用来存储属性值的区域,这是一种基于Hash的数据存储机制,效率肯定低于传统属性,不过这些效率损失不足以影响我们。插一句,牺牲一点点性能来换取强大的功能是DotNet的一贯做法,呵呵

 关于为DependencyProperty的赋值,实际上和传统的属性没有太大区别,XAML和 code中都可以为其赋值:
code中就不介绍了,和传统属性赋值相同,在XAML中,使用一个XML属性即可:
<l:ClassMyDependency MyString="11111" MyString1="22222" x:Key="myclass" />

l是实现定义的名字空间前缀,MyString是一个DependencyProperty,MyString1是一个普通属性,实际上这两个属性都能实现XAML下的赋值。
这一句XAML如果翻译成C# code大概是这个样子:
DependencyProperty主要功能是为了能让XAML代码为后台属性赋值,这是错误的。
不过使用XAML使用DependencyProperty也是有道理的。至于具体为什么,我准备在后续的POST里面会详细的说明。



WPF中ProgressBar上的文本_wpf

        ClassMyDependency myclass  =  

new  ClassMyDependency();

WPF中ProgressBar上的文本_wpf

        myclass.MyString = "

11111 " ;

WPF中ProgressBar上的文本_wpf

        mycalss.MyString1 = "

22222 " ;

网上有一些地方介绍说

 转自:



WPF中ProgressBar上的文本_wpf

         public   string

 MyString

WPF中ProgressBar上的文本_wpf_03

WPF中ProgressBar上的文本_设计模式_04

        

WPF中ProgressBar上的文本_设计模式_05

{

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_06

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_07

            get 

WPF中ProgressBar上的文本_设计模式_05

{ return (string)GetValue(myStringProperty); }

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_06

WPF中ProgressBar上的文本_WPF中ProgressBar上的文本_07

            set 

WPF中ProgressBar上的文本_设计模式_05

{ SetValue(myStringProperty, value); }

WPF中ProgressBar上的文本_.net_12

        }

WPF中ProgressBar上的文本_wpf