• 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方面的问题,可以给我留言,感谢大家浏览

  • 相关阅读:
    这些诗词你知道一句,却不知全诗!
    二十二、事件绑定及深入
    二十一、事件对象
    二十、事件入门
    十九、动态加载脚本和样式
    十八、DOM元素尺寸和位置
    十七、DOM操作表格及样式
    十六、DOM进阶
    十五、DOM基础
    正确使用volatile场景--状态标志
  • 原文地址:https://www.cnblogs.com/stswordman/p/800190.html
Copyright © 2020-2023  润新知