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);

}

}

其中的GetValue和SetValue都是调用父类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 = ”名称“
 
            }

WPF的依赖属性的更多相关文章

  1. wpf 的依赖属性只能在loaded 事件之后才能取到

    wpf 的依赖属性只能在loaded 事件之后才能取到,在构造函数的  InitializeComponent(); 之后取不到 wpf 的依赖属性只能在loaded 事件之后才能取到,在构造函数的  ...

  2. WPF 中依赖属性的继承(Inherits)

    WPF中依赖属性的值是是可以设置为可继承(Inherits)的,这种模式下,父节点的依赖属性会将其值传递给子节点.例如,数据绑定中经常使用的DataContextProperty: var host ...

  3. WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性

    原文:WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性 如果你要自定义一个图片按钮控件,那么如何在主窗体绑定这个控件上图片的Source呢? ...

  4. WPF的依赖属性和附加属性(用法解释较全)

    转:https://www.cnblogs.com/zhili/p/WPFDependencyProperty.html 一.引言 感觉最近都颓废了,好久没有学习写博文了,出于负罪感,今天强烈逼迫自己 ...

  5. WPF利用依赖属性和命令编写自定义控件

    以实例讲解(大部分讲解在代码中) 1,新建一个WPF项目,添加一个用户控件之后在用户控件里面添加几个控件用作测试, <UserControl x:Class="SelfControlD ...

  6. WPF: 只读依赖属性的介绍与实践

    在设计与开发 WPF 自定义控件时,我们常常为会控件添加一些依赖属性以便于绑定或动画等.事实上,除了能够添加正常的依赖属性外,我们还可以为控件添加只读依赖属性(以下统称"只读属性" ...

  7. WPF 自定义依赖属性

      原博客地址:http://www.cnblogs.com/DebugLZQ/archive/2012/11/30/2796021.html    DependencyObject和Dependen ...

  8. [转]WPF的依赖属性是怎么节约内存的

    WPF升级了CLR的属性系统,加入了依赖属性和附加属性.依赖属性的使用有很多好处,其中有两点是我认为最为亮眼的: 1)节省内存的开销; 2)属性值可以通过Binding依赖于其它对象上,这就使得我的数 ...

  9. WPF 之 依赖属性与附加属性(五)

    一.CLR 属性 ​ 程序的本质是"数据+算法",或者说用算法来处理数据以期得到输出结果.在程序中,数据表现为各种各样的变量,算法则表现为各种各样的函数(操作符是函数的简记法). ...

随机推荐

  1. Delphi 根据快捷方式路径取源文件地址

    unit Unit1;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, ...

  2. Oracle VM Virtual 下CentOS不能自动获取IP地址

    在CentOS配置网卡开机自动获取IP地址: vi /etc/sysconfig/network-scripts/ifcfg-eth0 将 ONBOOT="no" 改为 ONBOO ...

  3. Xutils 源码解析【转】

    原文:http://my.oschina.net/u/1538627/blog/395098 目录[-] 1. 功能介绍 2. 详细设计 2.1 View模块 2.1.1 总体设计 2.1.2 流程图 ...

  4. 【代码优化】坚持使用Override注解

    对于传统程序猿,注解里面最重要的就是Override注解了.这里的注解,都是指仅仅能用在方法中的声明, 她表示被注解的方法用于覆盖了父类的一个声明,假设坚持使用这个注解,能够防止一大类的非法错误. & ...

  5. iOS开源项目推荐|下拉刷新

    MJRefresh - 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明. CBStoreHouseRefresh ...

  6. 关于NSRunLoop和NSTimer的深入理解

    一.什么是NSRunLoop NSRunLoop是消息机制的处理模式 NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠 NS ...

  7. JS中checkbox组件的使用

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  8. iOS之XIB拖拽scrollView

    在使用storyboard和xib时,我们经常要用到ScrollView,还有自动布局AutoLayout,但是ScrollView和AutoLayout 结合使用,相对来说有点复杂.根据实践,我说一 ...

  9. Nginx高性能服务器安装、配置、运维 (4) —— Nginx服务、架构及其信号

    五.Nginx服务.架构及其信号 (1)Nginx服务的查看 1.netstat -antp 查看Nginx是否在80端口运行: 2.ps aux|grep nginx 查看nginx相关进程: 发现 ...

  10. Jquery获得控件值的方法

    一 Jquery获得服务器控件值的方法 由于ASP.NET网页运行后,服务器控件会随机生成客户端id,jquery获取时候不太好操作,google了下,总结有以下3种方法: 服务器控件代码:<a ...