1

From google, a lot of articles said that DependencyProperty is static because it has a KeyValue mechanism to maintain the value of each instance of the object.

But the problem is that, if we call GetValue / SetValue against the DependencyProperty, how does it identify each instance and generate the key so as to read / save the values from the HashTable for different instance of the object?

For example: if we create 2 instance of TestDp and then set value for TestDProperty of both instances, how does SetValue identify each instance and save the DependencyProperty value into the hash table accordingly?

I've checked the code for GetValue & SetValue of DependencyObject, but I still cannot figure out how it distinguish each instance. The code this.LookupEntry(dp.GlobalIndex) will pickup the EntryIndex but I'm not sure how the GlobalIndex is generated to distinguish each instance of the object.

 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);
            }
        }
    }
mind1n
  • 1,196
  • 3
  • 15
  • 34
  • Not sure I understand your question but you call `GetValue`/`SetValue` on current instance of `DependencyObject`. Also `dpTest` should be named `TestDProperty` and CLR wrapper should be called `TestD` and name of registered property _"TestD"_ – dkozl Nov 04 '14 at 12:46
  • ***set value for TestDProperty of both instances*** when you do this, you of course have to call the `SetValue` on ***different instances***, so it knows where to save the data separately. Note that the data are shared only when they have the ***default value***, once they change for some specific instance, they will no longer be shared. – King King Nov 04 '14 at 12:50
  • I've checked the code for GetValue & SetValue of DependencyObject, but I still cannot figure out how it distinguish each instance. The code this.LookupEntry(dp.GlobalIndex) will pickup the EntryIndex but I'm not sure how the GlobalIndex is generated to distinguish each instance of the object. – mind1n Nov 04 '14 at 13:31
  • 1
    @mind1n `DependencyProperty` definition is static but `this.GetValue(...)` and `this.SetValue(...)` are **instance methods of `DependencyObject`** so will be called on current instance just as `this.LookupEntry(...)` – dkozl Nov 04 '14 at 13:49
  • http://stackoverflow.com/questions/19441453/why-dependency-properties-in-wpf-has-to-be-static and http://wpftutorial.net/DependencyProperties.html – blfuentes Nov 04 '14 at 13:52

2 Answers2

1

The GetValue of DependencyObject will call GetValueEntry and consume the EntryIndex which you've mentioned. However, it doesn't seems to generate any key based on the instance information.

Mark Yuan
  • 850
  • 1
  • 8
  • 17
  • 2
    Right, there is only a global index for each DP, generated at the time the property is registered. This serves as the 'key'. There is no instance-specific key. – Mike Strobel Nov 04 '14 at 13:58
0

Abbreviations used:

DP=DependencyProperty

dp#=DP instances, e.g, DP1

DO=DependencyObject

dp#=DO instances

Good good question, but I don't think the accepted answer and comments really got what you're asking, what a pity. A more clarified question might be:

How a DependencyObject instance stores its local DependencyProperty(s) and retrieves it(them) by GetValue and SetValue?

According to your description, you're on the write way to explore out the way, what you should do is to track down the source code a little bit more:

DependencyObject.SetValue

DependencyObject.GetValue

Before digging into details, bear in mind that one of the advantages the dependency mechanism offers is helping to Reduced memory footprint. So you can roughly imagine how it works: at the very beginning, each DO instance has zero local DPs; and once it set a local DP by invoking the according SetValue, it allocates some space in memory to store it. Although the description is far from the truth, at least it gives you a preliminary grasp.

DependencyProperty

First, let's focus on the DP. As we know, each DP instance will be registered only once, and DP has a private static field int GlobalIndexCount, which increments by 1 each time a new DP instance is registered. Accordingly, each DP instance has a GlobalIndex, a possible example might be as:

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)

Btw, all DP instances are maintained by Hashtable PropertyFromName which is also a static field of class DependencyProperty. Bear in mind that each DP class instantiates only once.

DependencyObject

Second, let's have a look at DO. Each DO instance maintains an array: private EffectiveValueEntry[] _effectiveValues; which stores all the local DP instances it needs. EffectiveValueEntry has two properties:

  1. PropertyIndex: exactly GlobalIndex of a specific DP instance
  2. Value: the local value of the DP setted by SetValue

Suppose we have a DO class defined as below:

// 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;

Now _effectiveValues in do1 looks like this

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

where EntryIndex is returned by the function LookupEntry you mentioned. For situation in do2:

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

All the EffectiveValueEntry stored in _effectiveValues are sorted by GlobalIndex

The keypoint

Now it comes to the core of you puzzle: when a DO instance tries to get a DP, it use the DP's GlobalIndex to search its private field _effectiveValues, if found, a local DP value is returned; else, a default or inherited value is returned. Actually, the true story is much more complicated, see Value resolution strategy.

When it comes to write instead of read, similar stories happen, only by not reading but modifying _effectiveValues.

Tomingsun
  • 129
  • 1
  • 11