WPF - Dependency Properties

In .Net 1.1/2.0, a typical CLR property looks like this,
// Private field
private int _postId;

// Public property that wraps the private field
public int PostId{
    get { return _postId; }
    set { _postId= value; }
}

For a regular CLR property, the property value is read directly from a private class member. WPF introduces a new construct called a dependency property, which can get its value from different sources and the actual value resolution occurs dynamically at run-time based on some precedence rules.

For example, a TextBox‘s Text property, which is a dependency property, can get its value from a style, a trigger, an animation, or locally (among others). Consider the following XAML,
<Grid.Resources>
    <Style x:Key="TextBoxBaseStyle" TargetType="TextBox">
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Text" Value="Trigger setter text" />
            </Trigger>
        </Style.Triggers>
        <Setter Property="Text" Value="Property setter text" />
    </Style>
</Grid.Resources>

<!-- The local value of the Text property is set here -->
<TextBox x:Name="MyTextBox" Height="30" Width="100" 
    Text="Local value text" Style="{StaticResource TextBoxBaseStyle}" />

If we observe closely in above sample, the TextBox‘s Text (dependency) property is set in three places. So which one applies? If we run this, the TextBox starts out with the text "Local value text", even though we’ve set a Style that says Text should be "Property setter text". Why? This is because, when the WPF property system tried to resolve the Text value at run-time, the local value has precedence over a Style setter.

The precedence rules are (higher to lower),
  1. Active animations
  2. Local value
  3.  Style triggers
  4. Style setters
  5. Theme style
  6. Inheritance
  7. Default value (from dependency property metadata) 
As we have seen, a local value has higher precedence than a Style trigger or a Style setter. The Text dependency property depends on these different property value providers, each of which is checked in turn at run-time to get the property value. This also explains, how triggers are able to revert back the value when they are done. When the trigger stops changing the value, the WPF property system looks down the list for the next value provider that can supply a value; the trigger changes are thus temporary.

Now say we want to remove the dependency property’s local value so that the Text value can come from elsewhere (like a Style). The local value can be erased by,
this.MyTextBox.ClearValue(TextBox.TextProperty);
 
    // Note that these, will not remove the local value because
    // we're still setting a local value (to empty or null).
    //this.MyTextBox.Text = string.Empty;
    //this.MyTextBox.Text = null;

Once the local value is erased, you’ll see the Text changed to "Property setter text", and mouse over text to "Trigger setter text". Thus, the Text (dependency) property can get its value from different sources (local, style, trigger), and the run-time value depends a set of precedence rules. See the example, how to create dependency property?
// A dependency property is usually wrapped in a regular CLR property. This wrapper is not necessary,
// we can directly call GetValue/SetValue, but it’s useful if the dependency property needs to be set via XAML.
// Note that at runtime WPF calls the underlying GetValue/SetValue methods directly, bypassing the wrappers.
public int MyValue
{
    get { return (int)GetValue(MyValueProperty); }
    set { SetValue(MyValueProperty, value); }
}

// A dependency property definition
public static readonly DependencyProperty MyValueProperty =
            DependencyProperty.Register(
                "MyValue",              // Name of the dependency property
                typeof(int),            // Type of the dependency property
                typeof(MyClass),        // Type of the owner
                new PropertyMetadata(
                    0,                                            // The default value of the dependency property
                    new PropertyChangedCallback(OnValueChanged),  // Callback when the property changes
                    new CoerceValueCallback(CoerceValue)),        // Callback when value coercion is required
                new ValidateValueCallback(IsValidValue));     // Callback for custom validation

// The validation callback
private static bool IsValidValue(object value) { /* Validate the set value */ }
 
// The coercion callback
private static object CoerceValue(DependencyObject d, object value) { /* Adjust the value without throwing an exception */ }
 
// The value changed callback 
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ /* Called every time the dependency property value changes */ }

Dependency properties can also be read-only. A dependency property can only be created on a class which derives from the DependencyObject class, but since this class is very high up the WPF class hierarchy, this is not much of a concern.

Some of the advantages of dependency properties are,
  1. XAML friendly: Dependency properties can be set in XAML (via a CLR property wrapper) 
  2. Change notifications and validation: Get change notifications and validate property values by registering callbacks.
  3. Value inheritance: Dependency property values can be inherited from up the logical tree.
  4. Reduced memory: Since dependency properties are static, they save per-instance memory compared to regular CLR properties (which are based on per instance fields). 
We can also listen in to dependency property changes,
// We have to hook into TextBox’s Text property.
DependencyPropertyDescriptor textDescr = 
                  DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof(TextBox));
 
if (textDescr != null)
{
    textDescr.AddValueChanged(myTextBox, delegate
        {
            // Add your property changed logic here...
        });
}

Comments

  1. An example cannot be any better than this one. Loved the way its demonstrated here. Full marks.

    ReplyDelete
  2. Anonymous12/09/2015

    Many articles saying that DP value resolve dynamically but no one has provided example. Excellent explanation given here with example how DP resolve dynamically. Also got that answer of why trigger changes are temporary. Good one, Keep it up Man :)

    ReplyDelete
  3. Anonymous12/30/2015

    Simple and to the point. well done. pls keep posting.

    ReplyDelete
  4. HI explanation is goood but its not working for setting the text using style.

    ReplyDelete
  5. It will work while removing the Text="Local value text"

    ReplyDelete



  6. All are saying the same thing repeatedly, but in your blog I had a chance to get some useful and unique information, I love your writing style very much, I would like to suggest your blog in my dude circle, so keep on updates.


    SAP training in Chennai

    ReplyDelete
  7. First is to thank you for all this informative posts you give us for free; i bet all of us are happy.
    Such a great idea of yours! You have been a big help for me. Thanks a lot. more post for interesting topic. Great!

    SAP training in Chennai

    ReplyDelete
  8. This article creates a new hope and inspiration with in me. Thanks for sharing article like this. The way you have stated everything above is quite awesome. Keep blogging like this. Thanks.

    SAP training in Chennai

    ReplyDelete
  9. Anonymous7/10/2016

    This is the best way to explain Dependency properties in WPF.Lot of other blogs are there regarding this but none has able to explain it so easily. Thanks a lot. Do post this kind of simplified explanations.

    ReplyDelete
  10. My Arcus offer java training with 100% placement. Our java training course that includes fundamentals and advance java training program with high priority jobs. java j2ee training with placement having more exposure in most of the industry nowadays in depth manner of java .

    java training in chennai

    ReplyDelete
  11. Anonymous3/12/2017

    nice copy and paste article
    who is the dumb sob unit inch goat humper who posted this crap
    sure love the source code project available for download rofl

    ReplyDelete
  12. Excellent post! Thank you for Sharing. We are the best erp software providers in chennai. For more details call +91 9677025199 or email us on info@bravetechnologies.in
    erp in chennai

    ReplyDelete
  13. Thank you for taking time to provide us some of the useful and exclusive information with us.

    ReplyDelete

Post a Comment

Popular posts from this blog

Facade Design Pattern

Auto Scroll in Common Controls

Convert typed library (.tlb) to .net assembly?