WPF依赖属性(续)(3)依赖属性存储
在之前的两篇,很多朋友参与了讨论,也说明各位对WPF/SL计数的热情,对DP系统各抒已见,当然也出现了一些分歧. 以下简称DP为依赖属性
总结下上文:
- 讨论了DP的内存问题
- 讨论了依赖属性与附加属性的区别
下面我们继续讨论DP的存储.
存储依赖属性
(1)确保DP的唯一性
所有的DP由一个内部静态的哈希表(PropertyFromName)维护,一个对象定义的DP属性键值不可以重复,相同键值的DP可以定义在其他对象中,为确保属性唯一性,使用DP属性键值和对象的HashCode组成,内部定义了一个FromNameKey对象,如下
private class FromNameKey
{
// Fields
private int _hashCode;
private string _name;
private Type _ownerType; // Methods
public FromNameKey(string name, Type ownerType)
{
this._name = name;
this._ownerType = ownerType;
this._hashCode = this._name.GetHashCode() ^ this._ownerType.GetHashCode();
} public override int GetHashCode()
{
return this._hashCode;
}
}
以下为内部精简代码,忽略其他部分
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
{
FromNameKey key = new FromNameKey(name, ownerType);
if (PropertyFromName.Contains(key))
{
throw new ArgumentException(SR.Get("PropertyAlreadyRegistered", new object[] { name, ownerType.Name }));
}
DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
PropertyFromName[key] = dp;
return dp;
}
(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会被记录下来,保存到内部的一个列表中.如下代码
var people = new DPCustomPeople();
people.SetValue(DPCustomPeople.AgeProperty, 0);
AgeProperty的值将会被保存起来.
若要获取DP对象的本地DP值,DependencyObject公开了一个GetLocalValueEnumerator方法,可以获取该列表,
也可以使用ReadLocalValue方法读取一个DP的本地值
注意:GetValue方法如果本地值为空则返回默认值,但ReadLocalValue则会返回DependencyProperty.UnsetValue
如下测试代码
static void Main(string[] args)
{
var people = new DPCustomPeople();
Console.WriteLine("Before SetValue");
PrintLoaclValue(people);
Console.WriteLine();
people.SetValue(DPCustomPeople.AgeProperty, 0);
Console.WriteLine("After SetValue");
PrintLoaclValue(people); } static void PrintLoaclValue(DependencyObject obj)
{
var enumerator = obj.GetLocalValueEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine("Property:" + enumerator.Current.Property + "/Value:" + enumerator.Current.Value);
}
}
输出结果:
![]()
多属性值(属性百宝箱)
WPF具有强大的绑定功能,当初学WPF时,往往会把对属性的赋值与绑定混淆了,对于这个绑定功能也是非常的陌生,是如何实现的,我们且不讨论这一议题.来看看维护这份多属性值的数据结构EffectiveValueEntry,测试以下代码
people.SetValue(DPCustomPeople.AgeProperty, 25);
people.SetValue(DPCustomPeople.NameProperty, "Clingingboy");
我们将在DispatcherObject内部看到,一个变量名为_effectiveValues的数组
![]()
这就意味着对DP的修改要此_effectiveValues关联起来,那么DP的GlobaIndex就起到了作用
注意:DP一旦创建,GlobaIndex就固定了,但每个DP对象的_effectiveValues则是动态创建的,所以在赋值与取值的时候,要将其关联起来,内部采用了LookupEntry方法,根据DP的索引值,去列表中找到索引,并返回索引结果
EntryIndex entryIndex = this.LookupEntry(dp.GlobalIndex);
struct EntryIndex
{
private uint _store;
public EntryIndex(uint index);
public EntryIndex(uint index, bool found);
public bool Found { get; }
public uint Index { get; }
}
同时其内部还具备多个操作EffectiveValueEntry的方法
![]()
这篇先到这里,这部分还未完
WPF依赖属性(续)(3)依赖属性存储的更多相关文章
- WPF依赖属性(续)(2)依赖属性与附加属性的区别
原文:WPF依赖属性(续)(2)依赖属性与附加属性的区别 接上篇,感谢各位的评论,都是认为依赖属性的设计并不是为了节省内存,从大的方面而讲是如此.样式,数据绑定,动画样样都离不开它.这篇 ...
- WPF依赖属性(续)(1)
原文:WPF依赖属性(续)(1) 之前有写过几篇文章,详细地介绍了依赖属性的基本使用方法,如果你不想了解其内部实现机制的话,那么通过那两篇文章的介绍,足以应付平时的应用 ...
- WPF入门教程系列十一——依赖属性(一)
一.依赖属性基本介绍 本篇开始学习WPF的另一个重要内容依赖属性. 大家都知道WPF带来了很多新的特性,其中一个就是引入了一种新的属性机制——依赖属性.依赖属性出现的目的是用来实现WPF中的样式.自动 ...
- WPF学习(5)依赖属性
今天我们来学习WPF一个比较重要的概念:依赖属性.这里推荐大家看看周永恒大哥的文章,讲的确实很不错.我理解的没那么深入,只能发表一下自己的浅见.提到依赖属性,不得不说我们经常使用的传统的.net属性, ...
- WPF教程四:字段、属性、依赖项属性的演变过程
这个章节主要讲解属性是什么,为什么会演变出依赖项属性,依赖属性的优势是什么.以及如何更好的使用属性和依赖项属性. 一.属性 属性是什么. 翻了好几本C#的书和微软的文档,我觉得对属性讲解比较好理解的就 ...
- 【WPF学习笔记】之依赖属性
概述: Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能.这些服务通常统称为 WPF 属性系统.由 ...
- WPF系列 —— 控件添加依赖属性(转)
WPF系列 —— 控件添加依赖属性 依赖属性的概念,用途 ,如何新建与使用.本文用做一个自定义TimePicker控件来演示WPF的依赖属性的简单应用. 先上TimePicker的一个效果图. 概念 ...
- WPF系列 —— 控件添加依赖属性
依赖属性的概念,用途 ,如何新建与使用.本文用做一个自定义TimePicker控件来演示WPF的依赖属性的简单应用. 先上TimePicker的一个效果图. 概念 和 用途:依赖属性是对传统.net ...
- 在 WPF 中获取一个依赖对象的所有依赖项属性
原文:在 WPF 中获取一个依赖对象的所有依赖项属性 本文介绍如何在 WPF 中获取一个依赖对象的所有依赖项属性. 本文内容 通过 WPF 标记获取 通过设计器专用方法获取 通过 WPF 标记获取 p ...
随机推荐
- 想在子线程里面触发的信号的槽函数在子线程执行,信号槽连接必须使用DirectConnection 方式(即使跨线程,也可以强迫DirectConnection,而不能是AutoConnection)
Qt多线程的实现 1.继承QThread,重新run 2.继承Object,调用moveToThread方法 两种方法各有利弊:主要参考:http://blog.51cto.com/9291927/1 ...
- 3、C++快速入门
参考书籍: C++程序设计教程_第二版_钱能 //篇幅较少,适合快速学习 C++ Primer Plus 第六版 中文版 //篇幅较大,讲的非常详细 C++一般必须包含的头文件是#inc ...
- SetForegroundWindow
SetForegroundWindow 函数功能:该函数将创建指定窗口的线程设置到前台,并且激活该窗口.键盘输入转向该窗口,并为用户改各种可视的记号.系统给创建前台窗口的线程分配的权限稍高于其他线程. ...
- 使用纯CSS3实现一个3D旋转的书本
有一些前沿的电商站点已经開始使用3D模型来展示商品并支持在线定制,而当中图书的展示是最为简单的一种, 无需复杂的建模过程,使用图片和CSS3的一些变换就可以实现更好的展示效果,简洁而有用. 书本的3D ...
- [Elm] Installing and setting up Elm
Before writing any Elm we need to first install the runtime locally. In this lesson we install the E ...
- Codeforces 138C(区间更新+离散化)
题意:有n棵树在水平线上,给出每棵树的坐标和高度,然后向左倒的概率和向右倒的概率,和为1,然后给出了m个蘑菇的位置,每一个蘑菇都有一个魔法值,假设蘑菇被压死了,也就是在某棵树[a[i] - h[i], ...
- Seagate-保修验证(za25shrx)
保修验证 http://support.seagate.com/customer/zh-CN/warranty_validation.jsp Seagate 保修验证 End User ...
- php实现 字符个数统计
php实现 字符个数统计 一.总结 一句话总结: 1.php字符转ascii码函数? ord() 6 if(ord($input[$i]) < 128 and 0 < ord($input ...
- 常用服务器ftp、ssh
1. Linux常用服务器构建-ftp服务器 ftp服务器 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为"文传协议". 用于Int ...
- pthread_join/pthread_exit的使用方法解析
官方说法: 函数pthread_join用来等待一个线程的结束.函数原型为: extern int pthread_join __P ((pthread_t __th, void **__thread ...