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

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

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

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

  1. 1: public class NormalObject

  1. 2: {

  1. 3: private string _unUsedField;

  1. 4:

  1. 5: private string _name;

  1. 6: public string Name

  1. 7: {

  1. 8: get

  1. 9: {

  1. 10: return _name;

  1. 11: }

  1. 12: set

  1. 13: {

  1. 14: _name = value;

  1. 15: }

  1. 16: }

  1. 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的方法。

完整的代码如下:

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

举例

举例:修改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. HTTPResponse.read([amt]):只能read一次

    业务需要:我要写个tanx模拟器,给DSP发竞价请求. 下面是部分代码: def PostDataToDSP(self,url,postdata): headers = { 'Content-Type ...

  2. 使用viewpager实现广告条轮询的效果

    先上效果图: viewpager是google在v4-support包中提供的,使用时与listview类似,度需要提供一个adapter, 只不过viewpager提供的是PagerAdapter ...

  3. 标准I/O库之格式化I/O

    本篇博文内容摘自<UNIX环境高级编程>(第二版),仅作个人学习记录所用.关于本书可参考:http://www.apuebook.com/. 一.格式化输出 执行格式化输出处理的是4个pr ...

  4. Io_Language

    Object ancestor := method ( prototype := self proto if (prototype != Obejct, writeln ("Slots of ...

  5. 移动平台作业——天气预报——天气数据的获得——为应用申请百度ak码

    需求: 可切换城市 可实时更新(按钮或手势或下拉刷新) 可现实未来三日的天气 不限制横屏或者竖屏,不限制布局样式,但要求得到的数据均需显示(北京.天气数据.天气图标) 提示: 获得实时天气数据(任选一 ...

  6. javascript进击(三)简介

    JavaScript 表单验证(可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证) 被 JavaScript 验证的这些典型的表单数据有: 用户是否已填写表单中的必填项目? 用户输 ...

  7. 转:oracle ebs po模块一揽子采购协议小结

    转自:http://yedward.net/?id=193 oracle ebs po模块一揽子采购协议小结 本文总结oracle ebs采购订单(po)模块一揽子采购协议的相关知识,总结如下: 1. ...

  8. 【排障】使用DiskGenius修复0扇区损坏

    用PE引导启动进入PE后打开DiskGenius软件 "硬盘"图形菜单------选择驱动器符号(例如C) 主界面中显示该硬盘的分区格式为FAT32,起始柱面0,起始磁头65. 在 ...

  9. ImageView的属性android:scaleType

    ImageView的属性android:scaleType,即 ImageView.setScaleType(ImageView.ScaleType). android:scaleType是控制图片如 ...

  10. div置于页面底部

    一直对于页面置底有一些困惑,下面这个例子不知道能不能解决 <!DOCTYPE html> <html lang="en"> <head> < ...