【问题标题】:How WPF DependencyProperty pickup the key to distinguish each instance of an object and seek the values of the DependencyProperty?WPF DependencyProperty 如何获取区分对象的每个实例并查找 DependencyProperty 值的键?
【发布时间】:2014-12-31 08:38:00
【问题描述】:

来自google,很多文章说DependencyProperty是静态的,因为它有一个KeyValue机制来维护对象每个实例的值。

但问题是,如果我们针对 DependencyProperty 调用 GetValue / SetValue,它如何识别每个实例并生成密钥以便从 HashTable 中读取/保存对象的不同实例的值?

例如:如果我们创建2个TestDp实例,然后为两个实例的TestDProperty设置值,SetValue如何识别每个实例并将DependencyProperty值相应地保存到哈希表中?

我检查了 DependencyObject 的 GetValue 和 SetValue 的代码,但我仍然无法弄清楚它是如何区分每个实例的。代码 this.LookupEntry(dp.GlobalIndex) 将获取 EntryIndex,但我不确定如何生成 GlobalIndex 以区分对象的每个实例。

 public class TestDp : DependencyObject
    {
        protected static DependencyProperty dpTest = DependencyProperty.Register("TestDProperty", typeof(string), typeof(TestDp));
        public string TestDProperty
        {
            get
            {
                var r = (string)GetValue(dpTest);
                return r;
            }
            set
            {
                SetValue(dpTest, value);
            }
        }
    }

【问题讨论】:

  • 不确定我是否理解您的问题,但您在 DependencyObject 的当前实例上致电 GetValue/SetValue。此外,dpTest 应命名为 TestDProperty,CLR 包装器应命名为 TestD 和注册属性的名称 "TestD"
  • 为两个实例的 TestDProperty 设置值 当你这样做时,你当然必须在 SetValue >不同的实例,因此它知道将数据分别保存在哪里。请注意,数据仅在具有默认值时才共享,一旦针对某些特定实例更改,将不再共享。
  • 我检查了 DependencyObject 的 GetValue 和 SetValue 的代码,但我仍然无法弄清楚它是如何区分每个实例的。代码 this.LookupEntry(dp.GlobalIndex) 将获取 EntryIndex 但我不确定如何生成 GlobalIndex 以区分对象的每个实例。
  • @mind1n DependencyProperty 定义是静态的,但 this.GetValue(...)this.SetValue(...)DependencyObject 的实例方法,因此将在当前实例上调用 this.LookupEntry(...)

标签: wpf dependency-properties dependencyobject


【解决方案1】:

使用的缩写:

DP=DependencyProperty

dp#=DP 实例,例如 DP1

=DependencyObject

dp#=DO 实例

好问题,但我认为接受的答案和 cmets 并没有真正得到你的要求,真可惜。一个更明确的问题可能是:

DependencyObject 实例如何存储其本地 DependencyProperty 并通过 GetValueSetValue 检索它(它们)?

根据你的描述,你正在写的路上摸索,你应该做的就是多追查源代码:

DependencyObject.SetValue

DependencyObject.GetValue

在深入研究细节之前,请记住依赖机制提供的优势之一是帮助Reduced memory footprint。所以你可以大致想象一下它是如何工作的:一开始,每个 DO 实例的本地 DP 为零;一旦通过调用SetValue 设置本地DP,它就会在内存中分配一些空间来存储它。虽然描述与事实相去甚远,但至少给了你一个初步的把握。

依赖属性

首先,让我们关注 DP。我们知道,每个 DP instance 将被注册一次,并且 DP 有一个私有 static 字段int GlobalIndexCount,每个增加 1注册新 DP 实例的时间。因此,每个 DP instance 都有一个GlobalIndex,一个可能的例子可能是:

DP instances GlobalIndex
dp1 0
dp2 1
dp3 2
Current static field GlobalIndexCount for DP
3 (which will be assigned to next registered DP instance)

顺便说一句,所有 DP 实例都由Hashtable PropertyFromName 维护,这也是DependencyProperty 类的静态字段。请记住,每个 DP 类只实例化一次。

依赖对象

其次,让我们看看 DO。每个 DO 实例维护一个数组:private EffectiveValueEntry[] _effectiveValues;,其中存储了它需要的所有 本地 DP 实例。 EffectiveValueEntry 有两个属性:

  1. PropertyIndex:正是特定 DP 实例的 GlobalIndex
  2. ValueSetValue设置的DP的本地值

假设我们有一个 DO 类定义如下:

// Keep declaration only and omit trivial code
public class MyDependencyObject : DependencyObject
{
  protected static DependencyProperty Test1Property;
  protected static DependencyProperty Test2Property;
  protected static DependencyProperty Test3Property;
}

MyDependencyObject do1...;
do1.Test1 = 1;
do1.Test3 = 3;
MyDependencyObject do2...;
do2.Test2 = 2;

现在do1 中的_effectiveValues 看起来像这样

EntryIndex.Index PropertyIndex (equiv. GlobalIndex for DP), sorted Value Description
0 0 1 Local value for Test1Property
1 2 3 Local value for Test3Property

其中EntryIndex 由您提到的函数LookupEntry 返回。对于do2中的情况:

Entry index PropertyIndex (equiv. GlobalIndex for DP), sorted Value
0 1 Local value for Test2Property

_effectiveValues中存储的所有EffectiveValueEntry都按照GlobalIndex排序

关键点

现在进入谜题的核心:当 DO 实例尝试获取 DP 时,它使用 DP 的 GlobalIndex 搜索其私有字段 _effectiveValues,如果找到,则返回本地 DP 值;否则,返回默认值或继承值。其实真实的故事要复杂的多,见Value resolution strategy

当涉及到 write 而不是 read 时,会发生类似的故事,只是不是阅读而是修改_effectiveValues

【讨论】:

    【解决方案2】:

    DependencyObject 的 GetValue 将调用 GetValueEntry 并使用您提到的 EntryIndex。但是,它似乎没有根据实例信息生成任何密钥。

    【讨论】:

    • 对,每个DP只有一个全局索引,是在属性注册时生成的。这充当“关键”。没有特定于实例的键。
    猜你喜欢
    • 2017-01-28
    • 2012-07-31
    • 2011-01-06
    • 2016-09-26
    • 2013-02-16
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多