zoukankan      html  css  js  c++  java
  • WPF的依赖属性

    Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR)属性的功能,这些服务通常统称为 WPF 属性系统。由 WPF 属性系统支持的属性称为依赖项属性。

      这段是MSDN上对依赖属性(DependencyProperty)的描述。主要介绍了两个方面,WPF中提供了可用于扩展CLR属性的服务;被这个服务支持的属性称为依赖属性。

      单看描述,云里雾里的,了解一个知识,首先要知道它产生的背景和为什么要有它,那么WPF引入依赖属性是为了解决什么问题呢?

    属性是我们很熟悉的,封装类的字段,表示类的状态,编译后被转化为get_,set_方法,可以被类或结构等使用。 一个常见的属性如下:

       1: public class NormalObject
       2: {
       3:     private string _unUsedField;
       4:  
       5:     private string _name;
       6:     public string Name
       7:     {
       8:         get
       9:         {
      10:             return _name;
      11:         }
      12:         set
      13:         {
      14:             _name = value;
      15:         }
      16:     }   
      17: }

    在面向对象的世界里,属性大量存在,比如Button,就大约定义了70-80个属性来描述其状态。那么属性的不足又在哪里呢?

      当然,所谓的不足,要针对具体环境来说。拿Button来讲,它的继承树是Button->ButtonBase->ContentControl->Control->FrameworkElement->UIElement->Visual->DependencyObject->…

      每次继承,父类的私有字段都被继承下来。当然,这个继承是有意思的,不过以Button来说,大多数属性并没有被修改,仍然保持着父类定义时的默认值。通常情况,在整个Button对象的生命周期里,也只有少部分属性被修改,大多数属性一直保持着初始值。每个字段,都需要占用4K等不等的内存,这里,就出现了期望可以优化的地方:

    • 因继承而带来的对象膨胀。每次继承,父类的字段都被继承,这样,继承树的低端对象不可避免的膨胀。
    • 大多数字段并没有被修改,一直保持着构造时的默认值,可否把这些字段从对象中剥离开来,减少对象的体积

    依赖属性的优点

      回过头来,总结一下依赖属性的优点:

    • 优化了属性的储存,减少了不必要的内存使用。
    • 加入了属性变化通知,限制、验证等,
    • 可以储存多个值,配合Expression以及Animation等,打造出更灵活的使用方式。

    总结

      借助于依赖属性,WPF提供了强大的属性系统,可以支持数据绑定、样式、动画、附加属性等功能。这篇文章主要是简略的实现了一个从属性到依赖属性的发展过程,当然,具体和WPF的实现还有偏差,希望朋友们都能抓住这个主要的脉络,更好的去玩转它。

      除了依赖属性的实现,还有一些很重要的部分,比如借助于依赖属性提出的附加属性,以及如何利用依赖属性来更好的设计实现程序,使用依赖属性有哪些要注意的地方。呵呵,那就,下篇吧。

           有一个小技巧,需要申明一个依赖属性并使用CLR属性封装时,只需要输入propdp,vs就会给出一个提示,连按两次tab键,一个标准被依赖属性就申明好了,继续按tab键,可以修改依赖属性的各个参数。

    怎么样才能使一个属性成为依赖项属性呢?

    首先,属性所在的类要直接或间接继承DependencyObject。这个类生成的对象表示一个具有依赖项属性的对象,这些对象,都能享用WPF的属性系统(属性系统主要是计算属性的值,并提供有关值已更改的系统通知)方面的服务。

    这个类有两个比较重要的方法,GetValue(返回当前对象依赖项属性的当前有效值)和SetValue(设置依赖项属性的本地值)。

    其实,属性对应的字段必需是公有,静态,只读的,类型为DependencyProperty。即public static readonly DependencyProperty 字段名,同时字段的命名也有规范,属性名+Property,字段在定义时,通过DependencyProperty.Register来实注册属性(只有注册了,才能使用WPF属性系统的服务)。

    Register方法有三种重载,如下:

    名称

    说明

    Register(String, Type, Type)

    使用指定的属性名称、属性类型和属性所在对象的类型。

    Register(String, Type, Type, PropertyMetadata)

    使用指定的属性名称、属性类型、属性所在对象的类型和属性元数据注册依赖项属性。

    Register(String, Type, Type, PropertyMetadata, ValidateValueCallback)

    使用指定的属性名称、属性类型、属性所在对象的类型、属性元数据和属性的值验证回调来注册依赖项属性。

    Register中,各个参数解释如下:

    String:依赖属性的名字(不加Property,即字段的名字);

    Type:属性的类型;

    Type:属性所属对象的类型;

    PropertyMetadata:依赖项对象的属性元数据,是一个PropertyMetadata类型,可能赋初始值。PropertyMetadata有一个object的构造函数;

    ValidateValueCallback:表示用作回调的方法,这个类型是一个委托,用于验证依赖项属性的值的有效性,因为是委托,故它的构造参数为一个方法名。

    最后,来构造依赖属性,与普通的属性有所区别:

    Public 属性类型 属性名

    {

            Get

     {

    return (属性类型)this.GetValue(字段名);

                        }

        Set

     {

    this.SetValue(字段名, value);

     }

    }

    其中的GetValueSetValue都是调用父类DependencyObject的方法。

    完整的代码如下:

     

    代码 
    
    Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 class MyClass : DependencyObject
        {
            public static readonly DependencyProperty MyfieldProperty = DependencyProperty.Register("Myfield", typeof(int), 
    typeof(MyClass), new PropertyMetadata(0), new ValidateValueCallback(new MyClass().MyValidateMethod)); public int Myfield { get { return (int)GetValue(MyfieldProperty); } set { SetValue(MyfieldProperty, value); } } public bool MyValidateMethod(object value) { return true;//这里实现验证 } }

     

    举例

    举例:修改DataGrid的表头

    (1)PlotView.xml.cs文件:

       public string ColumnName5
            {
                get { return (string)GetValue(ColumnName5Property); }
                set { SetValue(ColumnName5Property, value); }
            }
            public static readonly DependencyProperty ColumnName5Property =
                DependencyProperty.Register("ColumnName5", typeof(string), typeof(PlotView), new UIPropertyMetadata("", new PropertyChangedCallback(ColumnName5PropertyCall)));
            private static void ColumnName5PropertyCall(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                PlotView send = d as PlotView;
                if (send.PlotViewDataGrid.Columns.Count > 6)
                {
                    send.PlotViewDataGrid.Columns[0].Header = (string)e.NewValue;
                }
            }

     (2)MainView.xml文件:

      <DataTemplate DataType="{x:Type local:PlotViewModel}" x:Key="PlotTemplate">
                <local:PlotView  ColumnName5="{Binding ColumnName5}"/>
            </DataTemplate>

    (3)在PlotViewModel.cs文件

           public string ColumnName5
            {
                get
                {
                    return ((PlotModel)Model).columnName5;
                }
                set
                {
                    if (((PlotModel)Model).columnName5 != value)
                    {
                        ((PlotModel)Model).columnName5 = value;
                    }
                    RaisePropertyChanged("ColumnName5");
                }
            }

    (4)在MainViewModel.cs文件:

       if (true)
                {
                    ((PlotViewModel)this.PlotViewModel).ColumnName0 = "时间"
                    
                }
                else
                {
                    ((PlotViewModel)this.PlotViewModel).ColumnName0 = ”名称“
     
                }

  • 相关阅读:
    Java集合类框架的基本接口有哪些?
    JSR303校验 —— hibernate-validator实现
    JSON和对象或集合间的转换
    Servlet 单例、多线程
    session.invalidate()
    request获取各种路径
    动态加载类并实例化对象 —— newInstance
    js 事件冒泡和事件捕获
    js事件绑定
    css 选择器和优先级
  • 原文地址:https://www.cnblogs.com/zzlp/p/3457237.html
Copyright © 2011-2022 走看看