微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

WPF基础到企业应用系列7――深入剖析依赖属性六

十五. 模拟依赖属性实现

  古人有”不入虎穴焉得虎子“的名句,我们今天也试着入一入虎穴,探探依赖属性里面到底藏着什么不可告人的秘密,在往下讲之前,我们先来看一下DependencyObject DependencyProperty 以及PropertyMetadata到底包含哪些功能,如下面三幅图

2010-8-26 18-38-50

2010-8-26 18-52-44

2010-8-26 19-14-21

  通过前面三幅图,我们就可以了解WPF依赖属性系统的大体结构以及主要功能,再者通过前面我们对它的使用,对它的内部实现也有一个相对比较清晰 的认识,那么接下来要做的就是:借助Reflector+VS调试内部代码功能一起来研究其内部的实现原理。 本来想详细写清楚开发的过程,但是有点多,所以我打算直接讲这几个类。大家也可以通过这个思路来试一试,同时还可以参考Mono的源码、WF的依赖属性源 码等。这里要推荐的是周永恒的博客,此人对技术的理解很是透彻,博文虽少,但每篇都堪称经典,所以他的文章,我都通读三遍。虽然大多概念都懂,并且读到深 处也能产生共鸣,其最主要目的还是学习他这种”阐述问题的思路“,后来也和此人MSN聊过几次。所以这个依赖属性的框架在某些程度上也借鉴了他的一些写 法。

  有了前面的思路,首先定义DependencyProperty这个类,它里面存储前面我们提到希望抽出来的字段。DependencyProperty内部维护了一个全局的Map用来储存所有的DependencyProperty对外暴露一个Register方法用来注册新的DependencyProperty。当然,为了保证在Map中键值唯一,注册时需要根据传入的名字和注册类的的 HashCode取异或来生成Key。 所以我们就可以完成DependencyProperty类了,代码如下,介绍详见代码注释。:

public sealed class DependencyProperty
{ //全局的IDictionary用来储存所有的DependencyProperty
internal static IDictionary<int,DependencyProperty> properties = new Dictionary<int,175);">DependencyProperty>(); //存储元数据的集合
private List<PropertyMetadata> _MetadataMap = new PropertyMetadata>(); private static int globalIndex = 0; private PropertyMetadata def_Metadata; private bool attached; private string name; private int _index; private Type owner_type; private Type property_type; private Type validator_type; // 构造函数
private Dependencyproperty() { } //构造函数私有,保证外界不会对它进行实例化
private DependencyProperty(string name,175);">Type propertyType,175);">Type ownerType,175);">PropertyMetadata defaultMetadata) { this.name = name; property_type = propertyType; owner_type = ownerType; def_Metadata = defaultMetadata; } // 常用属性
public PropertyMetadata DefaultMetadata { get { return def_Metadata; } } public bool IsAttached { get { return attached; } } public int Index { get { return _index; } set { _index = value; } } public string Name { get { return name; } } public Type OwnerType { get { return owner_type; } } public Type PropertyType { get { return property_type; } } public Type ValidatorType { get { return validator_type; } } public override int GetHashCode() { return name.GetHashCode() ^ owner_type.GetHashCode(); } //注册依赖属性
public static DependencyProperty Register(string name,175);">Type ownerType) { return Register(name,propertyType,ownerType,new PropertyMetadata()); } //注册的公用方法,把这个依赖属性加入到IDictionary的键值集合中,Key为name和owner_type的GetHashCode取异,Value就是我们注册的DependencyProperty
public static PropertyMetadata defaultMetadata) { DependencyProperty property = new DependencyProperty(name,defaultMetadata); globalIndex++; property.Index = globalIndex; if (properties.ContainsKey(property.GetHashCode())) { throw new InvalidOperationException("A property with the same name already exists"); } //把刚实例化的DependencyProperty添加到这个全局的IDictionary种
properties.Add(property.GetHashCode(),property); return property; } //注册只读依赖属性
public static DependencyProperty RegisterReadOnly(string name,175);">PropertyMetadata typeMetadata) { DependencyProperty property = Register(name,typeMetadata); return property; } //注册附加依赖属性
public static DependencyProperty Registerattached(string name,175);">Type ownerType) { return Registerattached(name,175);">PropertyMetadata(),null); } public static PropertyMetadata defaultMetadata) { return Registerattached(name,defaultMetadata,175);">PropertyMetadata defaultMetadata,175);">Type validatorType) { Metadata); property.attached = true; property.validator_type = validatorType; return property; } //子类继承重写以及其他需要重写Metadata的时候使用
public void OverrideMetadata(Type forType,175);">PropertyMetadata
Metadata) { Metadata.Type = forType; _MetadataMap.Add(Metadata); } //获取元数据信息
public PropertyMetadata GetMetadata(Type type) { PropertyMetadata medatata = _MetadataMap.FirstOrDefault((i) => i.Type == type) ?? _MetadataMap.FirstOrDefault((i) => type.IsSubclassOf(i.Type)); if (medatata == null) { medatata = def_Metadata; } return medatata; } }

  有了DependencyProperty ,那么接下来就需要定义DependencyObject 来使用这个DependencyProperty 。首先使用DependencyProperty .Register方法注册一个新的DependencyProperty ,然后提供了GetValue和SetValue两个方法来操作刚刚构造的DependencyProperty 。这个时候我们看到一个简单的依赖属性系统已初见端倪了,详见代码注释。

namespace Realize_DPs
{
    public abstract class DependencyObject :  Idisposable
{ //添加一个List来记录修改信息
private EffectiveValueEntry> _effectiveValues = new EffectiveValueEntry>(); //属性包装器,通过它来访问依赖属性
public object GetValue(DependencyProperty dp) { //首先通过判断是否改动过,以此来决定是读元数据的认值还是改动了的值
EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index); if (effectiveValue.PropertyIndex != 0) { return effectiveValue.Value; } else
{ PropertyMetadata Metadata; Metadata = DependencyProperty.properties[dp.GetHashCode()].DefaultMetadata; return Metadata.DefaultValue; } } //属性包装器,通过它来设置依赖属性的值
public void SetValue(DependencyProperty dp,object value) { //首先通过判断是否改动过,以及改动过,则继续对改动过的元素赋值,否则对_effectiveValues增加元素
EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index); if (effectiveValue.PropertyIndex != 0) { effectiveValue.Value = value; } else
{ effectiveValue = new EffectiveValueEntry() { PropertyIndex = dp.Index,Value = value }; _effectiveValues.Add(effectiveValue); } } public void dispose() { //暂时还没有处理
} } internal struct EffectiveValueEntry
{ internal int PropertyIndex { get; set; } internal object Value { get; set; } } }

  前面有了DependencyProperty DependencyObject 类,那我们现在来新建一个比较重要的类 PropertyMetadata ,它的作用和功能很强大,我们这里只是简单进行了构建,如下代码

namespace Realize_DPs
{
    public delegate void SetValueOverride(DependencyObject d,object value);

    public delegate object GetValueOverride(DependencyObject d);

    public class PropertyMetadata
{ private object default_value; private DependencyPropertyOptions options = DependencyPropertyOptions.Default; private bool _sealed = false; private SetValueOverride set_value; private GetValueOverride get_value; private Attribute[] attributes; private Type type; // 构造函数重载
public PropertyMetadata() { } public PropertyMetadata(object defaultValue) { default_value = defaultValue; } public PropertyMetadata(DependencyPropertyOptions options) { this.options = options; } public PropertyMetadata(params Attribute[] attributes) { this.attributes = attributes; } public PropertyMetadata(object defaultValue,params Attribute[] attributes) { default_value = defaultValue; this.attributes = attributes; } public PropertyMetadata(object defaultValue,175);">DependencyPropertyOptions options) { default_value = defaultValue; this.options = options; } public PropertyMetadata(DependencyPropertyOptions options,175);">Attribute[] attributes) { this.options = options; this.attributes = attributes; } public PropertyMetadata(object defaultValue,175);">Attribute[] attributes) { this.options = options; default_value = defaultValue; this.attributes = attributes; } public PropertyMetadata(object defaultValue,175);">GetValueOverride getValueOverride,175);">SetValueOverride setValueOverride) { this.options = options; default_value = defaultValue; set_value = setValueOverride; get_value = getValueOverride; } public PropertyMetadata(object defaultValue,175);">SetValueOverride setValueOverride,175);">Attribute[] attributes) { this.options = options; default_value = defaultValue; set_value = setValueOverride; get_value = getValueOverride; this.attributes = attributes; } // 常用属性
public object DefaultValue { get { return default_value; } set { default_value = value; } } public GetValueOverride GetValueOverride { get { return get_value; } set { get_value = value; } } public bool IsMetaProperty { get { return (options & DependencyPropertyOptions.Metadata) == DependencyPropertyOptions.Metadata; } } public bool IsNonSerialized { get { return (options & DependencyPropertyOptions.NonSerialized) == DependencyPropertyOptions.NonSerialized; } } public bool IsReadOnly { get { return (options & DependencyPropertyOptions.Readonly) == DependencyPropertyOptions.Readonly; } } protected bool IsSealed { get { return _sealed; } } public DependencyPropertyOptions Options { get { return options; } set { options = value; } } public SetValueOverride SetValueOverride { get { return set_value; } set { set_value = value; } } public Type Type { get { return type; } set { type = value; } } protected virtual void Merge(PropertyMetadata baseMetadata,175);">DependencyProperty dp) { // 实现元数据继承之间的合并
} protected virtual void OnApply(DependencyProperty dependencyProperty,175);">Type targettype) { // 当元数据被这个属性应用,OnApply就会被触发,在此时元数据也将被密封起来。
} } }

前面我们实现了一个简单的依赖属性系统,现在就得先测试一下其功能代码如下:

class Program : DependencyObject
{ public static readonly DependencyProperty CounterProperty; static Program() { //注册依赖属性Counter
CounterProperty = DependencyProperty.Register("Counter",typeof(double),typeof(Program),175);">PropertyMetadata(8.0)); } //属性包装器,暴露读写接口
public double Counter { get { return (double)GetValue(CounterProperty); } set {SetValue(CounterProperty,value); } } static void Main(string[] args) { Program pro = new Program(); Console.WriteLine("读取元数据设置的认值: "+pro.Counter.ToString()); Program pro2 = new Program(); pro2.Counter = 22.5; "通过SetValue设置改变了的值: " + pro2.Counter.ToString()); Console.ReadLine(); } }

那么测试结果为:

2010-8-26 0-50-36

利用VS自带的类图,可以看到刚才我们实现的这个依赖属性类及类之间的关系图:

2010-8-26 0-49-19

由于上面的代码在很多方面都很粗糙,所以希望大家能下载代码进行改造,同时也希望给出反馈。

十六. 本文总结

  这篇文章洋洋洒洒写了很多,我们现在简单回顾一下:在开篇之前我们会先介绍比本篇更重要的一些东西,然后插播了一段”云计算之旅“的广告(广告费很昂贵

PHP?refimg= + this.src)" alt="" src="http://img.jb51.cc/vcimg/static/loading.png" src="http://www.zu14.cn/coolemotion/emotions/zz_1.gif">

,所以格外小心),作为最近几个月执着研究的东西,终于可以在下周和大家见面了,所以心中甚是喜悦。在前面的两个内容之后我们正式进入本篇的主题——依赖 属性。依赖属性是WPF的核心概念,所以我们花费了大量的时间和篇幅进行论述,首先从依赖属性基本介绍讲起,然后过渡到依赖属性的优先级、附加属性、只读 依赖属性、依赖属性元数据、依赖属性回调、验证及强制值、依赖属性监听、代码段(自动生成) 等相关知识,最后我们模拟了一个WPF依赖属性的实现,对内部实现原理进行了一些研究。在接下来的三篇”剖析路由事件”、”剖析命令”、”剖析绑定”也会 采用这篇文章的风格,希望能尽量说透,如果有误之处还希望各位能够批评指正!

十七. 相关代码下载

  在文章的最后,我们提供代码的下载,这几篇文章最重要的就是下载代码来细细研究,代码里面也添加了比较详细的注释,如果大家有什么问题,也可以和我联系,如果有不正确的地方也希望多多海涵并能给我及时反馈,我将感激不尽!

DependencyPropertiesDemo


上图就是整个代码包的结构图,下载链接DependencyPropertiesDemo.rar

十八.系列进度

· 8. 命令
· 9. WPF控件分类介绍与使用技巧(ContentControl、HeaderedContentControl…… Decorator)
· 10. 尺寸缩放、定位与变换元素
· 11. 资源
· 12. 数据绑定(基本、值转换、验证、集合的筛选、排序、分组、主从、数据提供者)
· 13. 样式
· 14. 模板
· 15. 多语言、皮肤和主题
· 16. 2D图形
· 17. 3D图形
· 18. 动画(几种动画的应用)
· 19. 音频、视频、语音
· 20. 文档、打印、报表
· 21. 用户控件和自定义控件
· 22. Win32、Windows Form以及ActiveX之间的互用性
· 23. 构建并部署应用程序(ClickOnce部署、微软setup /InstallShield+自动更新组件)
· 24. WPF的模式讲解及实例(MVC Demo)
· 25. WPF的模式讲解及实例(MVP Demo)
· 26. WPF的模式讲解及实例(MVVM Demo)
· 27. 性能优化(WPF项目的瓶颈)
· 28.一个完整WPF项目(普通架构版)
· 39. 一个完整WPF项目(MVVM架构版)
· 30. WPF 4.0新功能

原文地址:https://www.jb51.cc/javaschema/287477.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐