WPF Unleashed Chapter 3:Important New Concepts in WPF ---Dependency Properties

声明: 本译文仅供学习讨论,禁止用于商业用途,否则后果自负   

Dependency Properties   

      WPF引入了一种新型的属性:Dependency Property(以后简称DP).这个属性贯穿WPF的始终。它提供了对样式,自动数据绑定,动画等特性的支持。第一次遇到这个概念时,您可能会对它的合理性产生怀疑:DP的出现破坏了.NET类型的简单性,例如.NET原有的成员,属性,方法和事件都是非常简洁的(fields, properties,methods and events).但当您了解到DP所解决的问题之后,你就会接受它了。

       一个DP的值可以由多个提供者提供,这样可以在多方面及时地为其赋值。这些提供者可以是一个animation:连续不断地改变DP的值;也可以父元素:将值传递给它的子集元素等等。可以论证地,DP的一个最大的特性就是其内置的变更通知功能(Change Notification)。

      让属性拥有如此智能的特性的目的是为了将其应用到XAML中。WPF声明友好式(declarative-friendly)的设计的核心是为了重用这些属性。以Button控件为例,它一共有96个公共属性。在不添加任何程序代码的情况下,我们就可以在XAML中使用这些属性(或者通过设计工具).但是如果没有了DP中的底层实现,那么在不编写程序代码的情况下,就很难实现了。

     我们首先简单的看一下DP的实现,以便有针对性地对其进行讨论。然后再对“DP对.NET属性上的增强功能”进行深入研究:

      
  • Change notification      
  •   
  • Property value inheritance
  •   
  • Support for multiple providers

    如果要创建自定义控件,那么了解各个DP之间的细微差别是非常重要的。对于那些WPF的使用者来说,他们也需要知道什么是DP,以及DP是如何工作的。例如你可以只使用style和animate的DP。但您使用了WPF一段时间后,就会愿意将所有的属性都设置成DP了。   




A Dependency Property Implementation

      实际上,DP只是在.NET的正常属性添加上了额外的WPF底层结构。这些都是由WPF的API完成的。没有任何.NET语言(XAML除外)可以理解 DP。在List3.3中,示范了Button控件是如何有效创建IsDefault这个DP的:

      3.3     A Standard Dependency Property Implementation   
      public class Button : ButtonBase   
      {   
            // The dependency property   
            public static readonly DependencyProperty IsDefaultProperty;   
            static Button()   
            {   
                  // Register the property   
                  Button.IsDefaultProperty = DependencyProperty.Register(“IsDefault”,   
                  typeof(bool), typeof(Button),   
                  new FrameworkPropertyMetadata(false,   
                  new PropertyChangedCallback(OnIsDefaultChanged)));   
                  …   
            }   
            // A .NET property wrapper (optional)   
            public bool IsDefault   
            {   
                  get { return (bool)GetValue(Button.IsDefaultProperty); }   
                  set { SetValue(Button.IsDefaultProperty, value); }   
            }   
            // A property changed callback (optional)   
            private static void OnIsDefaultChanged(   
            DependencyObject o, DependencyPropertyChangedEventArgs e) { … }   
            …   
      }    
  
      静态的成员IsDefaultProperty就是一个DP,类型为System.Windows.DependencyProperty.根据管理,所有的DependencyProperty成员都是公共类型和静态类型的(public and Static),并且要以“Property”字符串结尾。DP通常会用DependencyProperty类的静态方法Register方法创建。 Register方法需要以下参数:DP的名称(例子中的IsDefault),属性类型(例子中的bool),该属性类型的所有者(Button)。 Register还有一些重载方法,您可以将一些元数据传递给这些方法。这些元数据可以决定属性如何被WPF对待,是否当属性值改变时进行回调,强制限定属性值或者验证属性值。List3.3的Button控件就调用了其中的一个重载。为DP设置了默认值,并且设置了变更通知(change notifications)的委托。

      最后,IsDefault这个传统.NET属性实现了自己的访问器(accessors).这个访问器由GetValue和SetValue两个方法组成。两个方法都是System.Windows.DependencyObject类的实例方法。现在介绍一下DependencyObject类, DependencyObject是一个非常底层的基类,所有的DP类都继承自该类。它的GetValue方法会返回最后一次调用SetValue方法时所设置的值,如果SetValue始终没有被调用过,则会返回属性在注册时设置的默认值。实际上IsDefault属性(有事也叫做属性包装器)并不是必须的,对于Button的调用者来说,可以直接调用GetValue/SetValue方法。但是使用了.NET属性会在代码的读写上更加自然,并且可以应用到XAML中。

   WARNING
.NET property wrappers are bypassed at run-time when setting dependency properties in XAML!

      XAML编译器在编译时会用到属性包装器,而在运行时WPF会直接调用底层的GetValue和SetValue方法。所以为了保持XAML代码与程序代码之间的一致,在属性包装器的GetValue和SetValue方法中绝对不能添加任何逻辑代码。如果您的确需要添加一些逻辑代码,可以写在变更通知的回调方法中。所有的WPF内置的属性包装器都遵循了这一原则。

      表面上,List 3.3中的代码在实现简单的布尔值属性上过于冗长。但实际上,GetValue和SetValue内部使用了一种高效的存储,稀少的存储系统。并且 IsDefaultProperty是个静态成员(而不是实例成员),所以DP节省了相对于传统.NET属性的每一个实例的内存。如果所有的WPF控件都使用实例属性(像大多数的.NET属性那样),那么就会消耗掉数量可观的内存,因为本地的数据会附到每个实例上去:Button控件都有96个成员, Label控件则有89个,再算上其他等控件的成员,所消耗掉的内存会非常之多。幸好Button的96属性中有78个是DP,Label的89个属性中有71是DP。

      实现DP的好处不仅在于内存方面,DP还将“属性的线程访问检查”,“所包含元素的重新呈现”等特性进行了集中化和标准化管理。例如,当一个属性改变时,要求元素UI刷新(比如改变Button控件的Background属性),只需要在注册属性时将 FrameworkPropertyMetadataOptions.AffectsRender传给 DependencyProperty.Register方法。而且DP还为我们带来另外3个特性(上文中提到过),我们会逐一查看这些特性。首先从变更通知(Change Notification)开始。

    
翻译小记:之前O翻译的文章最多1000字就打住了,从没有连续翻译像《WPF Unleash》过这么长的文章。呵呵,真把O累B了。 现在对那些大部头的作者/译者真是敬佩万分啊...

ps:发现自己真的没有排版的天分.....:(
就唠叨这么多吧,一会儿把下一篇贴上来

如果您有WPF方面的问题,可以给我留言,感谢大家浏览

posted on 2007-06-29 15:50  stswordman  阅读(2946)  评论(11编辑  收藏  举报