Skip to content

WPF Dependency Properties

In this article I will introduce you into the concept of WPF Dependency Properties.

Introduction

A WPF Dependency Property is a special property of type DependencyProperty. Dependency Properties are properties which are used in XAML. Ordinary .Net properties cannot be used to bind data on it or apply a style or an animation.

Dependency Properties can only be defined in classes which derive directly or indirectly from DependencyObject. This is the reason why DependencyObject is the top baseclass of all WPF Controls.

Example Dependency Property:

public Orientation Orientation { get { return (Orientation)GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register( "Orientation", typeof(Orientation), typeof(FlipView), new PropertyMetadata(Orientation.Horizontal));
Code language: JavaScript (javascript)

In the above code listing you can see the Dependency Property named OrientationProperty. Along with the Dependency Property you can add an ordinary .Net wrapper to access the Dependency Property in your code without writing GetValue/SetValue again and again. However, when you use the Dependency Property in XAML you use the Dependency Property definition instead of your .Net wrapper. The name to use in XAML will be ‘Orientation’ without the suffix ‘Property’ as defined in the first paramater in the DependencyProperty.Register method.

Usual places to define a Dependency Property are inside a Custom Control or in the code behind file of a User Control. But the reason to define a Dependency Property is the same for both places: You want to give a possibility to set properties like colors, input data source or any other settings from outside your control (in XAML).

Dependency Property value evalution order

The main difference between an ordinary .Net property and a Dependency Property is the value evaluation. A Dependency Property can have different sources where its final value can come from. First of all a Dependency Property can have a default value. In the listing above the default value is mentioned in the PropertyMetadata (=Orientation.Horizontal). This is the value that is taken when it isn’t set on other places. Other places can be e.g. inheritance, styles, triggers, local value, animation, and so on.

Brief description of the evaluation order:

  1. Animation
  2. Binding (Binding on the property in XAML)
  3. Local Value (set via SetValue or by means of the .Net property wrapper or via direct property set in XAML)
  4. TemplatedParent template properties. Elements defined inside a ControlTemplate or a DataTemplate have a TemplatedParent. For these elements the order of direct value sets and style triggers are changed:
    1. Style triggers
    2. Direct value set (via XAML property set)
  5. Style triggers (triggers from a style)
  6. Template triggers (triggers from a control template)
  7. Style setters
  8. Default theme style
  9. Inheritance (some properties can inherit its value from a parent)
  10. Default value (as defined in the PropertyMetadata on the property registration)

It is very important to understand this evaluation order and make use of it!

Example:

A common use case in styles is to set a property depending on a trigger. Imagine a Button which shall change its color when the user hovers over the button with the mouse.

Trigger inside a ControlTemplate of a Button:

<Trigger Property="IsMouseOver" Value="true"> <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
Code language: HTML, XML (xml)

The question now is what value will be take if the property IsMouseOver is ‘false’. Do I need to define a trigger for that condition as well? The answer is ‘No’. If the value is ‘false’ the Style Trigger (evaluation step 4.1) will no longer be taken as value source and thus the property evaluation order will be walked up to look for another value source. In our case we have a direct property set for the ‘Background’ property and thus evaluation step 4.2 will apply.

<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
Code language: HTML, XML (xml)

Outside a Control Template the evaluation order is different so that a local property set will always be of higher priority than a style trigger/setter.

Example:

<Button Content="Push me" Width="200" Height="80" Background="Blue"> <Button.Style> <Style TargetType="Button"> <Setter Property="Background" Value="Green"/> </Style> </Button.Style> </Button>
Code language: HTML, XML (xml)

The Background is set to Blue directly in the declaration of the Button and thus has priority (step 3 from the list above) before the Style Setter (step 7 in the list above).

Property Changed event handler

Usually, you need to perform some actions when a Dependency Property has changed in your WPF Control. In order to respond on it you can define an property changed event handler.

internal static readonly DependencyProperty VerticalScrollOffsetProperty = DependencyProperty.Register("VerticalScrollOffset", typeof(double), typeof(AnimatedItemsScrollViewer), new PropertyMetadata(0.0, new PropertyChangedCallback(OnVerticalScrollOffsetChanged))); private static void OnVerticalScrollOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var smoothScrollViewer = (AnimatedItemsScrollViewer)d; smoothScrollViewer.VerticalOffset = (double)e.NewValue; }
Code language: JavaScript (javascript)

The event handler is called whenever the value has changed. It doesn’t matter from what source it changed. It can be an animation, a style trigger, direct set or whatever.

Copyright (c) by Thomas Kemp, 2021