原文:WPF依赖属性(续)(3)依赖属性存储

 

       在之前的两篇,很多朋友参与了讨论,也说明各位对WPF/SL计数的热情,对DP系统各抒已见,当然也出现了一些分歧. 以下简称DP为依赖属性

总结下上文:

  • 讨论了DP的内存问题
  • 讨论了依赖属性与附加属性的区别

下面我们继续讨论DP的存储.

存储依赖属性

(1)确保DP的唯一性
所有的DP由一个内部静态的哈希表(PropertyFromName)维护,一个对象定义的DP属性键值不可以重复,相同键值的DP可以定义在其他对象中,为确保属性唯一性,使用DP属性键值和对象的HashCode组成,内部定义了一个FromNameKey对象,如下

  1. private class FromNameKey
  2. {
  3. // Fields
  4. private int _hashCode;
  5. private string _name;
  6. private Type _ownerType;
  7.  
  8. // Methods
  9. public FromNameKey(string name, Type ownerType)
  10. {
  11. this._name = name;
  12. this._ownerType = ownerType;
  13. this._hashCode = this._name.GetHashCode() ^ this._ownerType.GetHashCode();
  14. }
  15.  
  16. public override int GetHashCode()
  17. {
  18. return this._hashCode;
  19. }
  20. }

以下为内部精简代码,忽略其他部分

  1. public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
  2. {
  3. FromNameKey key = new FromNameKey(name, ownerType);
  4. if (PropertyFromName.Contains(key))
  5. {
  6. throw new ArgumentException(SR.Get("PropertyAlreadyRegistered", new object[] { name, ownerType.Name }));
  7. }
  8. DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
  9. PropertyFromName[key] = dp;
  10. return dp;
  11. }

(2)何时注册DP

由于DP是以静态方法注册的,所以当拥有此DP的对象初始化后则会注册该对象DP,我们来看下,当一个Window窗体拥有一些简单的元素初始化后,其DP的数量

依赖属性赋值与取值

在赋值与取值之前必须了解下情况

(1)DP不直接参与自身的存值与取值操作,而是由拥有DP的对象(依赖项对象,且称为DP对象)完成,该对象从DispatcherObject派生.使用GetValue和SetValue方法

(2)DP对象对DP进行赋值前,必须先索引DP,用内部键值索引太麻烦,则为内部加了一个Index索引值,可以用DependencyProperty .GlobalIndex拿到这个值,DP列表数据结构内部维护着一个列表可以根据Index进行索引,这样便于DP对象查询DP

维护本地依赖属性值

什么是本地DP值,即是你修改过的DP属性的值,而非采用默认的DP属性元数据中的值在之前介绍过,每个DP都拥有的一个默认值,现在必须要把DP与拥有该DP的对象联系起来.

DP对象内部维护着一份本地DP值列表,当DP有所修改,那么该DP会被记录下来,保存到内部的一个列表中.如下代码

  1. var people = new DPCustomPeople();
  2. people.SetValue(DPCustomPeople.AgeProperty, 0);

AgeProperty的值将会被保存起来.

若要获取DP对象的本地DP值,DependencyObject公开了一个GetLocalValueEnumerator方法,可以获取该列表,

也可以使用ReadLocalValue方法读取一个DP的本地值

注意:GetValue方法如果本地值为空则返回默认值,但ReadLocalValue则会返回DependencyProperty.UnsetValue

如下测试代码

  1. static void Main(string[] args)
  2. {
  3. var people = new DPCustomPeople();
  4. Console.WriteLine("Before SetValue");
  5. PrintLoaclValue(people);
  6. Console.WriteLine();
  7. people.SetValue(DPCustomPeople.AgeProperty, 0);
  8. Console.WriteLine("After SetValue");
  9. PrintLoaclValue(people);
  10.  
  11. }
  12.  
  13. static void PrintLoaclValue(DependencyObject obj)
  14. {
  15. var enumerator = obj.GetLocalValueEnumerator();
  16. while (enumerator.MoveNext())
  17. {
  18. Console.WriteLine("Property:" + enumerator.Current.Property + "/Value:" + enumerator.Current.Value);
  19. }
  20. }

输出结果:

多属性值(属性百宝箱)

WPF具有强大的绑定功能,当初学WPF时,往往会把对属性的赋值与绑定混淆了,对于这个绑定功能也是非常的陌生,是如何实现的,我们且不讨论这一议题.来看看维护这份多属性值的数据结构EffectiveValueEntry,测试以下代码

  1. people.SetValue(DPCustomPeople.AgeProperty, 25);
  2. people.SetValue(DPCustomPeople.NameProperty, "Clingingboy");

我们将在DispatcherObject内部看到,一个变量名为_effectiveValues的数组

这就意味着对DP的修改要此_effectiveValues关联起来,那么DP的GlobaIndex就起到了作用

注意:DP一旦创建,GlobaIndex就固定了,但每个DP对象的_effectiveValues则是动态创建的,所以在赋值与取值的时候,要将其关联起来,内部采用了LookupEntry方法,根据DP的索引值,去列表中找到索引,并返回索引结果

  1. EntryIndex entryIndex = this.LookupEntry(dp.GlobalIndex);
  1. struct EntryIndex
  2. {
  3. private uint _store;
  4. public EntryIndex(uint index);
  5. public EntryIndex(uint index, bool found);
  6. public bool Found { get; }
  7. public uint Index { get; }
  8. }

同时其内部还具备多个操作EffectiveValueEntry的方法

这篇先到这里,这部分还未完

WPF依赖属性(续)(3)依赖属性存储的更多相关文章

  1. WPF依赖属性(续)(2)依赖属性与附加属性的区别

    原文:WPF依赖属性(续)(2)依赖属性与附加属性的区别        接上篇,感谢各位的评论,都是认为依赖属性的设计并不是为了节省内存,从大的方面而讲是如此.样式,数据绑定,动画样样都离不开它.这篇 ...

  2. WPF依赖属性(续)(1)

    原文:WPF依赖属性(续)(1)                 之前有写过几篇文章,详细地介绍了依赖属性的基本使用方法,如果你不想了解其内部实现机制的话,那么通过那两篇文章的介绍,足以应付平时的应用 ...

  3. WPF入门教程系列十一——依赖属性(一)

    一.依赖属性基本介绍 本篇开始学习WPF的另一个重要内容依赖属性. 大家都知道WPF带来了很多新的特性,其中一个就是引入了一种新的属性机制——依赖属性.依赖属性出现的目的是用来实现WPF中的样式.自动 ...

  4. WPF学习(5)依赖属性

    今天我们来学习WPF一个比较重要的概念:依赖属性.这里推荐大家看看周永恒大哥的文章,讲的确实很不错.我理解的没那么深入,只能发表一下自己的浅见.提到依赖属性,不得不说我们经常使用的传统的.net属性, ...

  5. WPF教程四:字段、属性、依赖项属性的演变过程

    这个章节主要讲解属性是什么,为什么会演变出依赖项属性,依赖属性的优势是什么.以及如何更好的使用属性和依赖项属性. 一.属性 属性是什么. 翻了好几本C#的书和微软的文档,我觉得对属性讲解比较好理解的就 ...

  6. 【WPF学习笔记】之依赖属性

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

  7. WPF系列 —— 控件添加依赖属性(转)

    WPF系列 —— 控件添加依赖属性 依赖属性的概念,用途 ,如何新建与使用.本文用做一个自定义TimePicker控件来演示WPF的依赖属性的简单应用. 先上TimePicker的一个效果图. 概念 ...

  8. WPF系列 —— 控件添加依赖属性

    依赖属性的概念,用途 ,如何新建与使用.本文用做一个自定义TimePicker控件来演示WPF的依赖属性的简单应用. 先上TimePicker的一个效果图. 概念 和 用途:依赖属性是对传统.net ...

  9. 在 WPF 中获取一个依赖对象的所有依赖项属性

    原文:在 WPF 中获取一个依赖对象的所有依赖项属性 本文介绍如何在 WPF 中获取一个依赖对象的所有依赖项属性. 本文内容 通过 WPF 标记获取 通过设计器专用方法获取 通过 WPF 标记获取 p ...

随机推荐

  1. flink DataStream API使用及原理

    传统的大数据处理方式一般是批处理式的,也就是说,今天所收集的数据,我们明天再把今天收集到的数据算出来,以供大家使用,但是在很多情况下,数据的时效性对于业务的成败是非常关键的. Spark 和 Flin ...

  2. 【例题 6-2 UVA - 514】Rails

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 栈模拟一下就好. 每个输出段后面都有一个空行. 包括最后一个. [代码] #include <bits/stdc++.h> ...

  3. 【AtCoder ABC 075 C】Bridge

    [链接] 我是链接,点我呀:) [题意] 让你求出桥的个数 [题解] 删掉这条边,然后看看1能不能到达其他所有的点就可以了 [代码] #include <bits/stdc++.h> us ...

  4. Android layer-list的属性和使用具体解释

    Android layer-list的属性和使用具体解释.layer-list是用来多个图层堆叠显示的,借这个特性能够做一些特别的效果(比方:阴影.以下的效果等),也能够投机取巧. 1.代码片 < ...

  5. [Nuxt] Add CSS Libraries to Nuxt

    You can easily add CSS libraries to Nuxt using yarn or npm to install them, then simply adding them ...

  6. APK瘦身记,怎样实现高达53%的压缩效果

    作者:非戈@阿里移动安全,很多其它技术干货.请訪问阿里聚安全博客 1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式.关于这个话题事实上是一个老生常谈的题目.不论是公司内部.还是外 ...

  7. matplotlib学习之颜色样式

    一.颜色 1.内建八种默认颜色 蓝色 - 'b' 绿色 - 'g' 红色 - 'r' 青色 - 'c' 品红 - 'm' 黄色 - 'y' 黑色 - 'k' 白色 - 'w' 2.灰度 plt.plo ...

  8. link和@import引入外部样式的区别

    原文: 简书原文:https://www.jianshu.com/p/14f99062f29a 大纲 前言 1.隶属上的差别 2.加载顺序的不同 3.兼容性上的差别 4.使用DOM控制样式时的差别 5 ...

  9. Hadoop配置文件 分类: A1_HADOOP 2014-08-19 12:48 1157人阅读 评论(1) 收藏

    部分内容参考:http://www.linuxqq.net/archives/964.html  http://slaytanic.blog.51cto.com/2057708/1100974/ ha ...

  10. [Angular Router] Lazy loading Module with Auxiliary router

    Found the way to handle Auxiliary router for lazy loading moudle and erge load module are different. ...