Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do dependency/attached properties work internally and where are values stored?

I'm a little bit unclear with all this magic. As I understood dependency properties get inherited from the DependencyObject, so values are stored:

  • in the instance itself if value is assigned (in the local dictionary)
  • or taken from the link to a parent element if value is not specified.

    protected object GetValue(string propertyName)
    {
       if (LocalValues.ContainsKey(propertyName))
       {
          return LocalValues[propertyName];
       }
       return Parent.GetValue(propertyName);
    }
    

    Am I correct in this?

I also don't understand where are values for attached properties stored?

Control.FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
typeof(Control), new FrameworkPropertyMetadata(SystemFonts.MessageFontSize,
FrameworkPropertyMetadataOptions.Inherits));

Does AddOwner method call on Attached property assigns value to the instance field? When does this happen and where does the value go?

Thanks!

like image 995
elm Avatar asked Aug 12 '13 14:08

elm


2 Answers

Values for dependency properties are stored inside the objects (derived from DependencyObject) which we apply a property value to.

Let's take your TextElement.FontSizeProperty attached property for example:

<StackPanel TextElement.FontSize="20" ... >
  ...
</StackPanel>

XAML parser translates it to the following:

...
TextElement.SetFontSize(stackPanel, 20);
...

which is internally:

public static void SetFontSize(DependencyObject element, double value)
{
  element.SetValue(TextElement.FontSizeProperty, value);
}

So, setting TextElement.FontSize on a stackPanel object is the same as calling

stackPanel.SetValue(TextElement.FontSizeProperty, value)

SetValue() is a method defined in the DependencyObject class. Inside the method many complex things happen, but in the end the effective value of a dependency property is wrapped in a structure called EffectiveValueEntry and stored in the following instance field inside DependencyObject:

private EffectiveValueEntry[] _effectiveValues;
like image 178
WpfNewbie Avatar answered Sep 19 '22 14:09

WpfNewbie


The property system in WPF is pretty complex. MSDN really has a lot of information, but it is often hard to find. While there are many ways a DependencyProperty can be set, I'm not sure that you need to care where the values are stored.

For local values, you can assume that it is stored on the DependencyObject (again you shouldn't care where it is stored), with the caveat that they are not stored based on strings. It truly is associated with an instance of DependencyProperty. This is why you would want to add an owner to the property. If somebody sets TextElement.FontSize on your control, it is just like setting your local FontSize property.

As far as inheriting values for a property from a parent, this only happens with attached properties. From the MSDN entry for FrameworkPropertyMetadataOptions:

Although property value inheritance might appear to work for nonattached dependency properties, the inheritance behavior for a nonattached property through certain element boundaries in the runtime tree is undefined. Always use RegisterAttached to register properties where you specify Inherits in the metadata.

like image 20
Abe Heidebrecht Avatar answered Sep 22 '22 14:09

Abe Heidebrecht