Windbg调试WPF的依赖属性中提到了wpf的DependencyObject中DependencyProperty是怎样调试查看的。

从中我们看出DO(DependencyObject)与 DP(DependencyProperty)一些内部实现。

这篇文章我们就从源代码入手, 让大家了解下依赖对象中依赖属性的值的获取和赋值。
我们先看个DP注冊的样例:
public class MyStateControl : ButtonBase
{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

上述Code中MyStateControl是DO。StateProperty是DP
1.
当MyStateControl进行初始化, 首先会运行StateProperty, 由于它是静态字段。从而运行DependencyProperty.Register方法。

2.
这种方法内部调用了DP的构造方法。 Code例如以下:
  // Create property
            DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
3.
DP的构造方法例如以下:
  private DependencyProperty( string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
        {
            _name = name;
            _propertyType = propertyType;
            _ownerType = ownerType;
            _defaultMetadata = defaultMetadata;
            _validateValueCallback = validateValueCallback;
            Flags packedData;
            lock (Synchronized)
            {
                packedData = (Flags) GetUniqueGlobalIndex(ownerType, name);
                RegisteredPropertyList.Add( this);
            }
            if (propertyType.IsValueType)
            {
                packedData |= Flags.IsValueType;
            }
            if (propertyType == typeof (object))
            {
                packedData |= Flags.IsObjectType;
            }
            if (typeof (Freezable).IsAssignableFrom(propertyType))
            {
                packedData |= Flags.IsFreezableType;
            }
            if (propertyType == typeof (string))
            {
                packedData |= Flags.IsStringType;
            }
            _packedData = packedData;
        }
4.
第3点的Code中我们能够看到packedData初始值是 (Flags) GetUniqueGlobalIndex(ownerType, name);
GetUniqueGlobalIndex事实上是DP的私有静态变量GlobalIndexCount++得到的。

下来这段代码能够看出:
  [Flags]
        private enum Flags : int
        {
            GlobalIndexMask                           = 0x0000FFFF,
            IsValueType                               = 0x00010000,
            IsFreezableType                           = 0x00020000,
            IsStringType                              = 0x00040000,
            IsPotentiallyInherited                    = 0x00080000,
            IsDefaultValueChanged                     = 0x00100000,
            IsPotentiallyUsingDefaultValueFactory     = 0x00200000,
            IsObjectType                              = 0x00400000,
            // 0xFF800000   free bits
        }
 public int GlobalIndex
        {
            get { return (int) (_packedData & Flags.GlobalIndexMask); }
        }
_packedData的低4位即代表了StateProperty在整个DP数组RegisteredPropertyList中的索引。
5.
我们在构造里看到_packedData成员变量, 还记得我们“windbg怎样调试依赖属性”用到了它吗?
我们用 .formats 命令转换去掉_packedData高位得到了DP在DO中的存储索引。
通过第4和第5点, 想必大家已经对DP注冊有了了解

接下来我们再看下DO中怎样获取DP值。以及怎样设置DP值。
6.
首先我们说下DO设置DP,Code相似:
set { this.SetValue(StateProperty, value); }

能够看到我们通过DO的SetValue来给DP设置值。

7.
SetValue内部实现例如以下:
  private void SetValueCommon(
            DependencyProperty  dp,
            object              value,
            PropertyMetadata    metadata,
            bool                coerceWithDeferredReference,
            bool                coerceWithCurrentValue,
            OperationType       operationType,
            bool                isInternal)
        {
           。

。。。。。

            EntryIndex entryIndex = LookupEntry(dp.GlobalIndex);
          。。

。。。

大家能够看到DO依据DP的GlobalIndex在_effectiveValues数组中查找到EntryIndex, EntryIndex包括相应index和Value。假设没有查到则在_effectiveValues中插入并返回index。

(有兴趣能够看看LookupEntry的实现)
在数组中找到之后接下来就是往数组中赋值。代码相似(真实比以下更复杂):
 if (entryIndex.Found)
                {
                    newEntry = _effectiveValues[entryIndex.Index];
                }
               
然后调用UpdateEffectiveValue发送属性更改通知。

(还有其它一些Coerce相关代码,暂且不述)

 // fire change notification
                    NotifyPropertyChange(
                            new DependencyPropertyChangedEventArgs(
                                    dp,
                                    metadata,
                                    isAValueChange,
                                    oldEntry,
                                    newEntry,
                                    operationType));
通过上面我们能够了解依赖对象中的依赖属性的赋值实现, 我们接下来再看看取值。

8.
DO获取DP的值,Code相似:

get { return (Boolean)this.GetValue(StateProperty); }

9. 
GetValue内部实现例如以下:
   public object GetValue(DependencyProperty dp)
        {
           。。。
            // Call Forwarded
            return GetValueEntry(
                    LookupEntry(dp.GlobalIndex),
                    dp,
                    null,
                    RequestFlags.FullyResolved).Value;
        }
能够看出是先找到DP的索引。然后接下来从_effectiveValues数组中找到相应的值。

代码相似例如以下:

 entry = _effectiveValues[entryIndex.Index];
(当然当中也有一些值优先级的处理,从来获取到正确的值)

OK, 我们再回忆下Windbg中查看依赖对象的依赖属性的值的步骤, 1.得到依赖对象的值;2.得到依赖属性的值;3得到依赖属性的GlobalIndex。4.依据GlobalIndex去依赖对象中的_effectiveValues找到相应index的值。
是不是对DP和DO的一些实现更了解了呢?

WPF中DependencyObject与DependencyProperty的源代码简单剖析的更多相关文章

  1. WPF中的命令简介

    使用Prism委托命令Demo: WPF委托命令DelegateCommand的传参方式 在WPF中使用命令的步骤很简单 1.创建命令 2.绑定命令 3.设置命令源 4.设置命令目标 WPF中命令的核 ...

  2. 在WPF中实现玻璃模糊效果

    在WPF中实现玻璃模糊效果还是比较简单的,主要方式如下: 添加一个Rectangle或其它控件作为玻璃放到顶部图层 将底部图像作为Brush(大多数的时候用VisualBrush)填充到Rectang ...

  3. WPF中监视DependencyProperty的变化

    WPF中监视DependencyProperty的变化   周银辉 尽管一个类会提供很多事件,但有时候还是显得不够,比如说前两天我就以为WPF的ListBox控件会有ItemsSourceChange ...

  4. WPF中DataTemplateSelector的简单应用

    WPF中DataTemplateSelector的简单应用 DataTemplateSelector中文叫数据模板选择器,根据数据模型内的属性值选择不同的数据模板,多用于容器如listbox中,达到同 ...

  5. WPF中使用MVVM模式进行简单的数据绑定

    计划慢慢整理自己在WPF学习和工作应用中的一些心得和想法,先从一个简单的用法说起 在WPF中,XAML标记语言中绑定数据,而数据源就是指定为ViewModel类,而非界面本身的逻辑代码类 这样一定程度 ...

  6. WPF中的触发器简单总结

    原文 http://blog.sina.com.cn/s/blog_5f2ed5cb0100p3ab.html 触发器,从某种意义上来说它也是一种Style,因为它包含有一个Setter集合,并根据一 ...

  7. WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性

    原文:WPF 使用依赖属性(DependencyProperty) 定义用户控件中的Image Source属性 如果你要自定义一个图片按钮控件,那么如何在主窗体绑定这个控件上图片的Source呢? ...

  8. WPF中的简单水动画

    原文 https://stuff.seans.com/2008/08/21/simple-water-animation-in-wpf/ 很多年前(80年代中期),我在一家拥有Silicon Grap ...

  9. 简单的介绍下WPF中的MVVM框架

    最近在研究学习Swift,苹果希望它迅速取代复杂的Objective-C开发,引发了一大堆热潮去学它,放眼望去各个培训机构都已打着Swift开发0基础快速上手的招牌了.不过我觉得,等同于无C++基础上 ...

随机推荐

  1. 算法笔记_122:蓝桥杯第七届省赛(Java语言A组)试题解答

     目录 1 煤球数目 2 生日蜡烛 3 搭积木 4 分小组 5 抽签 6 寒假作业 7 剪邮票 8 取球博弈 9 交换瓶子 10 压缩变换   前言:以下试题解答代码部分仅供参考,若有不当之处,还请路 ...

  2. Discuz的sc 和tc版本有什么区别

    Discuz的sc 和tc版本有什么区别 简单的来说: sc 是tc 是繁体中文 简体中文Simplified Chinese 繁体中文traditional Chinese

  3. SwaggerUI+SpringMVC——构建RestFul API的可视化界面

    今天给大家介绍一款工具,这个工具眼下可预见的优点是:自己主动维护最新的接口文档. 我们都知道,接口文档是非常重要的,可是随着代码的不断更新,文档却非常难持续跟着更新,今天要介绍的工具,完美的攻克了这个 ...

  4. 修改Cygwin的默认启动路径

    原先启动Cygwin后,pwd显示: C:\Documents and Settings\Administrator@IBM-EBDC0EAC4B7 ~$ pwdC:\Documents and Se ...

  5. 小程序三:视图层之WXML

    WXML WXML(WeiXin Markup Language)是MINA设计的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. [1]数据绑定 1.1 简单绑定 数据绑定使用" ...

  6. eclipse里面的时间错误,比电脑系统时间慢了8个小时

    eclipse里面的时间错误,比电脑系统时间慢了8个小时 解决办法: 打开<eclipse安装目录>/eclipse.ini文件 在文件末尾追加 -Duser.timezone=Asia/ ...

  7. 原生php如何获取当前页面的url

    原生php如何获取当前页面的url? //php获取当前访问的完整url地址 function get_current_url(){ $current_url='http://'; if(isset( ...

  8. 通过配置CPU参数 worker_cpu_affinity 提升nginx性能

    简介 Nginx默认没有开启利用多核cpu,我们可以通过增加worker_cpu_affinity配置参数来充分利用多核cpu的性能.cpu是任务处理,计算最关键的资源,cpu核越多,性能就越好. 规 ...

  9. Git恢复之前版本的两种方法reset、revert(图文详解)

    一.问题描述在利用github实现多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,本文总结了两种解决方法:回退(reset).反做(reve ...

  10. 初步了解“C#反射”

    来源:http://zhidao.baidu.com/link?url=YzuEaWpYMxYV86bAFVmSAGYtXEzkJ_ndMyZ69QuvNJfikwXvlmtP42hAslGFS2uu ...