浅谈WPF依赖项属性
浅谈WPF依赖项属性
0. 引言
依赖项属性虽然在使用上和CLR属性一样,但是它是WPF特有的,不同于CLR属性。只是封装为我们常用CLR的属性,在语法使用上和CLR属性一样。WPF中一些功能:动画,属性绑定,样式等都是以依赖项属性为基础的。WPF中元素的属性大部分都是依赖项属性。
依赖项属性和CLR属性最主要的区别是:CLR属性是通过一个私有的字段来读取。而依赖项属性则是通过继承在DependencyObject
的GetValue()
和SetValue()
方法动态的读取属性值。
就是说当设置一个依赖项属性值时,并不是直接给一个对象的字段赋值,而是在一个DependencyObject
对象的字典中设置键值对。Key
值为属性的名称,Value
值为你要赋值的值。
为什么使用依赖项属性:
减少内存
当UI控件的90%以上的属性通常停留在初始值时,为每个属性存储字段会是一个巨大的消耗。依赖项属性则是只在实例中存储修改的属性,那些默认值只在依赖项属性中存储一次。(如字体属性,并不是每个元素都存储一个字体属性,字体属性只存储一次,其他元素则是继承该字体属性。即:值继承)值继承
当访问依赖项属性时,该属性值将通过使用一个值解析策略来解决:如果没有设置本地值,则依赖属性将导航到逻辑树,直到找到一个值为止。当在根元素上设置FontSize时,它将应用该根元素的所有子元素的所有文本块,除非在子元素中重新设置了FontSize值。更改通知
依赖属性有一个内置的变更通知机制。通过在属性元数据中注册一个回调,当属性值被更改时,就会得到通知。这也是数据绑定所使用的。
1. 自定义依赖项属性
如果希望原本不支持数据绑定,动画,或其他WPF功能的代码实现这些功能时,就要创建依赖项属性。
1.1 声明依赖项属性
声明一个DependencyProperty
类型的字段,表示依赖项属性的对象。该属性的值应该始终保持可用,同时为了保证在多个类之间共享该属性信息,必须将DependencyProperty
对象定义为与其类关联的静态字段,WPF为了确保在创建DependencyProperty
对象后不能修改该对象,所以所有的DependencyProperty
成员都是只读的。
(如:Margin属性,所有的类都共享该属性,所以该属性必须是与类本身关联。)
//声明一个当前时间的依赖项属性
public static readonly DependencyProperty CurrentTimeProperty;
1.2 注册依赖项属性
在使用该属性代码之前要先完成注册(即该属性和被注册的类和数据类型,默认值,及一些事件关联起来)完成,因此要在与其关联的静态构造函数中进行。WPF为了确保DependencyProperty
对象不能被直接实例化,使DependencyProperty
类没有公有的构造函数。只能使用静态方法DependencyPropery.Register()
创建DependencyProperty
实例。这些注册的值必须作为Register()
方法的参数来提供。
public class MyClockControl1
{
CurrentTimeProperty = DependencyProperty.Register( "CurrentTime", typeof(DateTime),
typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now),validateValueCallback);
static bool validateValueCallback(object data)
{
//自定义验证
return true;
}
}
Register()
注册方法一共有五个参数,其中前三个为必选,后两个为可选参数。
- 第一个参数:表示CLR属性的名称。
- 第二个参数:表示依赖项属性的数据类型
- 第三个参数:表示注册的类的类型
- 第四个参数:表示该依赖项属性的默认值
- 第五个参数:表示该依赖项属性的回调验证
每个依赖属性都提供了更改通知、值强制和验证的回调。这些回调可以通过FrameworkPropertyMetadata
来实现。
如:
new FrameworkPropertyMetadata( DateTime.Now, OnCurrentTimePropertyChanged, OnCoerceCurrentTimeProperty ),OnValidateCurrentTimeProperty );
1.2.1 值更改回调
值更改回调是一个静态方法,每当该属性值更改时,都会调用这个回调方法。
private static void OnCurrentTimePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
MyClockControl control = source as MyClockControl;
DateTime time = (DateTime)e.NewValue;
}
1.2.2 属性值强制回调验证
在执行属性验证回调前先执行该方法,尝试纠正不合法的属性值。
private static object OnCoerceTimeProperty( DependencyObject sender, object data )
{
if ((DateTime)data > DateTime.Now )
{
data = DateTime.Now;
}
return data;
}
1.2.3 属性验证回调
但依赖项属性的值发生变化时调用该回调方法。该回调方法验证属性值是否合法,如果不合法,返回false,抛出异常。
private static bool OnValidateTimeProperty(object data)
{
return data is DateTime;
}
1.3 添加属性包装器
依赖项属性的包装器,是通过DependencyObject的GetValue()和SetValue()方法来包装。
public DateTime CurrentTime
{
get { return (DateTime)GetValue(CurrentTimeProperty); }
set { SetValue(CurrentTimeProperty, value); }
}
完整的代码如下:
// Dependency Property
public static readonly DependencyProperty CurrentTimeProperty =
DependencyProperty.Register( "CurrentTime", typeof(DateTime),
typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now));
// .NET Property wrapper
public DateTime CurrentTime
{
get { return (DateTime)GetValue(CurrentTimeProperty); }
set { SetValue(CurrentTimeProperty, value); }
}
static bool validateValueCallback(object data)
{
//自定义验证
return true;
}
自定义一个依赖项属性,需要挺多的套路,当然这些套路不需要你一个一个代码来敲,在Visual Studio可以输入propdp
再点击两次tab
键,就可以创建依赖项属性模板。 只需修改模板的属性名称和类型即可。
模板代码如下:
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
2. 附加属性
附加属性也是一种依赖项属性。与其他依赖项属性不同的时,其他的依赖项属性是应用到被注册的类上,而附加属性则是应用到其他的类上。
比如:Canvas
的类的Top
和Left
等为附加属性,其他的元素并没有该属性,只有Canvas
类有,在使用Canvas.Top
时,如果为每个元素都定义一个这样的依赖项属性,那么就会大量的重复性代码,且不可维护更改。如果只在Canvas
类型上定义这个依赖项属性,其他的元素只继承使用该属性就好。附加属性就是这样。
附加属性的定义和依赖项属性的定义几乎一样。唯一不同的是注册是通过调用DependencyProperty.GegisterAttached()
方法来实现,且属性包装器为静态方法。
如:
public static readonly DependencyProperty TopProperty =
DependencyProperty.RegisterAttached("Top",
typeof(double), typeof(Canvas),
new FrameworkPropertyMetadata(0d,
FrameworkPropertyMetadataOptions.Inherits));
public static void SetTop(UIElement element, double value)
{
element.SetValue(TopProperty, value);
}
public static double GetTop(UIElement element)
{
return (double)element.GetValue(TopProperty);
}
至此就可以像使用普通的CLR属性一样使用WPF的依赖项属性。
如有不对,请多多指教!
参考列表:
浅谈WPF依赖项属性的更多相关文章
- [转]WPF 依赖项属性
from:http://blog.csdn.net/datoumimi/article/details/8033682 ps:环境限制,发的东西一长就会被拦截,所以删了一部分 UI软件中经常会用到大量 ...
- WPF依赖项属性不需要包装属性也可以工作
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...
- 学习WPF——初识依赖项属性
入门 首先创建一个依赖项属性 然后绑定父容器的DataContext到这个依赖项的实例 接着绑定子元素的属性到依赖项属性(注意Button的Content属性) 程序最终的运行结果: 说明 首先是 ...
- WPF学习系列之二 (依赖项属性)
依赖属性;(dependency property) 它是专门针对WPF创建的,但是WPF库中的依赖项属性都使用普通的.NET属性过程进行了包装.从而可能通过常规的方式使用它们,即使使用他们的代码不 ...
- WPF中的依赖项属性
Form cnblogs 桂素伟 随着WPF的推广,不得不重新拾起WPF来,因为这块的产品越来越多. 只能跟着MSDN来学了,所以想是在这里记录下学习的过程和对知识的理解. 先从最基本的吧,依赖项属性 ...
- 迟到的 WPF 学习 —— 依赖项属性
本章学习依赖项属性,英文原文 Dependency Property,它是传统 .Net Framework 属性的扩展,是 WPF 的专属,但所幸使用起来和传统属性几乎一样.WPF 元素所提供的大多 ...
- WPF中的依赖项属性(转)
出处:https://www.cnblogs.com/axzxs2001/archive/2010/04/25/1719857.html 随着WPF的推广,不得不重新拾起WPF来,因为这块的产品越来越 ...
- WPF的依赖项属性
WPF的依赖项属性 属性与事件是.NET抽象模型的核心部分.WPF使用了更高级的依赖项属性(Dependency Property)功能来替换原来.NET的属性,实现了更高效率的保存机制,还添加了附加 ...
- 在 WPF 中获取一个依赖对象的所有依赖项属性
原文:在 WPF 中获取一个依赖对象的所有依赖项属性 本文介绍如何在 WPF 中获取一个依赖对象的所有依赖项属性. 本文内容 通过 WPF 标记获取 通过设计器专用方法获取 通过 WPF 标记获取 p ...
随机推荐
- SpringBoot+Mybatis+Freemark 最简单的例子
springboot-sample 实现最简单的 SpringBoot + Mybatis + Freemarker 网页增删改查功能,适合新接触 Java 和 SpringBoot 的同学参考 代码 ...
- Elastic FileBeat 快速入门
背景 用过ELK(Elasticsearch, Logstash, Kibana)的人应该都面临过同样的问题,Logstash虽然功能强大:支持许多的input/output plugin.强大的fi ...
- Hadoop(十)Hadoop IO之数据完整性
前言 上一篇我分享了Hadoop的压缩和编解码器,在我们开发的过程中其实是经常会用到的,所以一定要去掌握.这一篇给大家介绍的是Hadoop的数据完整性! Hadoop用户在使用HDFS储存和处理数据不 ...
- JSON对象添加删除属性
假如目前我们有如下一个Json对象 var jsonObj={ 'param1':22, 'param2' :33 }; 增加属性: 我们现在向该对象jsonObj中添加一个新的属性字段:param3 ...
- POJ 1422 Air Raid
题目链接: http://poj.org/problem?id=1422 Description Consider a town where all the streets are one-way a ...
- css3中的关键帧技术分析应用
最近在研究网页加载进度效果的时候发现可以使用css3实现这个效果. 使用css3实现完全不需要图片,相比使用loading.gif的实现来说可能更快. 使用css3实现动态加载的效果,主要会涉及到几个 ...
- dedecms织梦上传图片302Error错误
很多客户反馈这样的问题,上传图片的时候会提示302错误,找不到原因,很着急,秀站网小编分析下如下解决办法,希望能帮助大家. 解决问题: 1:空间满了,请查看空间容量是否满了. 2:权限问题... 很多 ...
- [拾 得]pipe和xargs的恩怨情仇
Photo by Joshua Sortino on Unsplash 坚持知识分享,该文章由Alopex编著, 转载请注明源地址: http://www.cnblogs.com/alopex/ ...
- PostgreSql问题:ERROR: operator does not exist: timestamp without time zone > character varying
问题描述: ERROR: operator does not exist: timestamp without time zone > character varying 解决方法: //注意 ...
- linux libpcap的性能问题,请大家注意绕行。
内核代码中,ip_rcv是ip层收包的主入口函数,该函数由软中断调用.存放数据包的sk_buff结构包含有目的地ip和端口信息,此时ip层进行检查,如果目的地ip不是本机,且没有开启转发的话,则将包丢 ...