Why is it called a "DependencyProperty"?

When we create new classes and members we spend a lot of time and effort to make them as usable, understandable, and discoverable as possible. We follow the .Net Design Guidelines in general, and in particular we constantly look at how this new class relates to other classes, future plans, etc.

 

So we went through all that when naming DependencyProperty and DependencyObject. All told we probably spent hours just on the name. What dependency properties (DPs) boil down to in the end is property calculation and dependency tracking. Property calculation isn’t terribly distinctive, lots of properties do that, so the essence of a DP is really the dependency tracking, thus “Dependency” properties.

 

 

Here’s an example of that, actually one piece of sample code that shows several examples of dependency tracking:

 

<StackPanel TextBlock.FontSize="22" DataContext="Hello, world">

    <StackPanel.Resources>

        <Style TargetType="TextBlock">

            <Setter Property="FontWeight" Value="Bold" />

            <Style.Triggers>

                <Trigger Property="IsMouseOver" Value="True">

                    <Setter Property="Background" Value="Red" />

                </Trigger>

            </Style.Triggers>

        </Style>

    </StackPanel.Resources>

    <TextBlock Text="{Binding}" />

   

</StackPanel>

 

 

The properties of this TextBlock have quite a few dependencies:

· TextBlock.Text is dependent on the Binding, and the Binding is dependent on the DataContext in this case. The DataContext is inheriting down from the StackPanel, so the Text property is therefore also dependent on the shape of the tree; if the TextBlock is removed from the StackPanel, it’s Text property will update.

· TextBlock.FontSize is dependent on the tree as well. Here, you can see it’s inheriting from the StackPanel.

· All of the TextBlock properties depend on TextBlock.Style. For example, here TextBlock.FontWeight is coming from the Style.

· Similarly, TextBlock.Background depends on the Style, but here it’s being set in trigger. So TextBlock.Background in this case also depends on TextBlock.IsMouseOver.

 

Sometimes, if you write your own DP, you need to help with the dependency tracking. You do this by calling InvalidateProperty when a property needs to be re-calculated, usually because you reference it in a CoerceValueCallback.

 

For example, here’s a DP Foo and a companion (read-only) DP named FooPlus1. FooPlus1 just has a CoerceValueCallback that calculates “Foo+1”. Foo therefore has a PropertyChangedCallback that invalidates FooPlus1 whenever Foo changes.

 

//

// Foo property

//

public int Foo

{

    get { return (int)GetValue(FooProperty); }

    set { SetValue(FooProperty, value); }

}

public static readonly DependencyProperty FooProperty =

    DependencyProperty.Register("Foo", typeof(int), typeof(Window1),

                                new PropertyMetadata(FooChangedCallback));

static void FooChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)

{

    // Whenever Foo changes, we need to invalidate FooPlus1, so that

    // the DependencyProperty system knows to update it (call its

    // CoerceValueCallback again).

    (d as Window1).InvalidateProperty(Window1.FooPlus1Property);

}

//

// FooPlus1 Property

//

public int FooPlus1

{

    get { return (int)GetValue(FooPlus1Property); }

}

static readonly DependencyPropertyKey FooPlus1PropertyKey =

    DependencyProperty.RegisterReadOnly("FooPlus1", typeof(int), typeof(Window1),

                                new PropertyMetadata(0, null, CoerceFooPlus1Callback));

static readonly DependencyProperty FooPlus1Property = FooPlus1PropertyKey.DependencyProperty;

static object CoerceFooPlus1Callback(DependencyObject d, object baseValue)

{

    return (d as Window1).Foo + 1;

}