Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Demystifying Dependency Properties

I have read about dependency properties a lot on SO and other sites. But, really haven't found a great explanation and am still confused. I use both SL and WPF. Are they different in SL and WPF, in terms of implementation? Why do we really need them? Are they static means that their values are shared? Why was the reason MS introduced dependency properties?

like image 725
Sandbox Avatar asked Dec 03 '10 15:12

Sandbox


People also ask

What is advantage of dependency property?

Advantages of a Dependency Property The Dependency Property stores the property only when it is altered or modified. Hence a huge amount of memory for fields are free. It means that if no value is set for the property then it will return to the inheritance tree up to where it gets the value.

When should I use dependency properties in WPF?

Dependency properties are used when you want data binding in a UserControl , and is the standard method of data binding for the WPF Framework controls. DPs have slightly better binding performance, and everything is provided to you when inside a UserControl to implement them.


1 Answers

The answer is in the name itself, though the word "dependency" is so fraught with meaning in software development that it's not especially clear what that means.

A dependency property is a property on one object whose value depends on some other object. So, for instance:

  • The value of the FontFamily property of a TextBox can (and usually does) depend on the FontFamily property of its container. If you change the property on the container, the value on the TextBox changes.

  • The value of the Text property of a TextBox can depend on a bound data source. When the value of the bound property changes, the value of the Text property changes.

  • The value of the Opacity property of a Label can depend on an animation storyboard, in the common scenario where you've set up a UI element to fade in or fade out in response to some event.

  • The value of all kinds of properties on any UI element can depend on the style that you've applied to them.

The central concept behind dependency is that the thing that's depending should get the property value from the thing it's depending on. This is why a dependency property is implemented as a CLR property whose getter calls a method.

When the TextBox, or the thing that's rendering it, needs to know what its FontFamily is, the FontFamily getter calls the GetValue method. That method finds the value from the container, or animation, or binding, or whatever.

There's a lot of complexity in that method. If the value's inherited, for instance, it works in a way that's pretty analogous to how WPF finds styles in a resource dictionary: it looks in a local dictionary to find the value, and if there's no entry it looks in its parent's dictionary, and so on all the way up until it finds a value or reaches the top of the hierarchy, in which case it uses a default value.

If you look at the implementation of dependency properties, that's what you'll find. A dependency object has a dictionary that may or may not contain an entry for a given property. The GetValue method gets values from that dictionary (which is how objects with dependency properties can have local values that override what they're inheriting from), and if it doesn't find the value, it uses the metainformation about the property to figure out where it should look.

Since that metainformation is the same for every object in the class (i.e., TextBox.Text works the same for every TextBox), the dictionary it's stored in is a static property of the class.

So when you see code like this:

static Button()
{
   // Register the property
   Button.IsDefaultProperty = 
     DependencyProperty.Register("IsDefault",
     typeof(bool), typeof(Button),
     new FrameworkPropertyMetadata(false,
        new PropertyChangedCallback(OnIsDefaultChanged)));
}

what's happening is that the metainformation that defines the IsDefault property on all Button objects is being added to that dictionary. And when you see this:

public bool IsDefault
{
  get { return (bool)GetValue(Button.IsDefaultProperty); }
  set { SetValue(Button.IsDefaultProperty, value); }
}

what you're seeing is the getter method that looks up the property's value (from the local dictionary, the parent object, or whatever) based on that metainformation.

Remember how I said that the first place the getter looks to find a property's value is in the object's local dictionary? The SetValue method in the setter is how that entry gets added to the dictionary (if it's ever called, which it will only be if you're overriding the dependency by explicitly setting the property, i.e. saying "I want this TextBox to display text in Consolas irrespective of what the other controls in the window are using.").

A hugely significant benefit that we get from this kind of apparently-complex system is that dependency properties on objects only consume memory if they're set. If I create 10,000 TextBox controls and add them to a Window, not one of them actually contains a reference to a FontFamily object. That's 10,000 object references that I'm not allocating memory for, and that the garbage collector isn't checking. In fact, if a TextBox has 100 dependency properties (and it does, just about), whenever you create a TextBox, that's 100 backing fields you aren't allocating memory for. Dependency properties only consume memory if you explicitly set them. Since the vast majority of properties on UI objects never get explictly set, these are fantastic savings.

like image 172
Robert Rossney Avatar answered Oct 09 '22 13:10

Robert Rossney