If you are developing applications using Windows Presentation Foundation (WPF), you will frequently come across the term Dependency Property.
At first, a Dependency Property can look more complicated than a normal C# property. However, Dependency Properties are one of the fundamental features of WPF and are responsible for many powerful capabilities such as data binding, styles, templates, animations, property inheritance, and change notifications.
In this article, we will understand what a Dependency Property is, why WPF uses it, how to create one, and when you should use it in your WPF applications.
What is a Dependency Property?
A Dependency Property is a property whose value depends on the external sources, such as animation, data binding, styles, or visual tree inheritance. The Dependence property extends the CLR property, which means it provides some external service to CLR property like it is providing notification when the property has changed, data binding, and styling.
A class which defines a dependency property must be inherited from the DependencyObject class. Many of the UI controls class which are used in XAML are derived from the DependencyObjectclass and they support dependency properties, e.g. Button class supports the IsMouseOver dependency property.
Need of Dependency Property
Dependency Properties offer a lot of functionalities that you won’t get by using a CLR property. We can use Dependency property for the following reason
- If you want to set the style
- If you want data binding
- If you want to set with a resource (a static or a dynamic resource)
- If you want to support animation
Dependency Property vs. CLR Property
Dependency properties are stored in a dictionary of key/value pairs which is provided by the DependencyObject class. It also saves a lot of memory because it stores the property when changed. It can be bound in XAML as well. But CLR properties can directly read/write from the private member of a class by using getter and setter. In contrast, dependency properties are not stored in local objects.
Dependency property support notification, means whenever a property changes its value it provides notification in the Dependency Property using INotifyPropertyChange and also helps in data binding, whereas CLR Property does not support any notification
A Dependency Property can animate, set styles using style setters, and even provide templates for the control. Whereas CLR property does not support anything.
Dependency property also support callback feature, but CLR Property does not.
Advantages of a Dependency Property
- Less memory consumption
The Dependency Property stores the property only when it is altered or modified. Hence a huge amount of memory for fields are free.
- Property value inheritance
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.
- Change notification and Data Bindings
Whenever a property changes its value it provides notification in the Dependency Property using INotifyPropertyChange and also helps in data binding.
- Participation in animation, styles and templates
A Dependency Property can animate, set styles using style setters and even provide templates for the control.
- CallBacksWhenever a property is changed you can have a callback invoked.
- ResourcesYou can define a Resource for the definition of a Dependency Property in XAML.
- Overriding Metadata
You can define certain behaviours of a Dependency Property using PropertyMetaData. Thus, overriding a metadata from a derived property will not require you to redefine or re-implement the entire property definition.
<Window x:Class="WPFDependencyProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFDependencyProperty"
Title="MainWindow" Height="350" Width="604">
<Grid>
<Button Height="40"
Width="175"
Margin="10"
Content="Dependency Property">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</Window>
Creating a Dependency Property
To create a custom WPF dependency property, your class must derive from DependencyObject (or a subclass like UIElement or Control). The process requires registering a static property identifier and exposing it through a traditional C# property wrapper. follow the below points to create a dependency property
- Derive from
DependencyObjectThe WPF property system only recognizes dependency properties on classes that inherit from DependencyObject. Hence create a class like below by inhering
DependencyObject.public class MyCustomControl : Control { // Your dependency property logic goes here } - Register the Dependency Property (The Identifier)
Declare a
public static readonlyfield of typeDependencyProperty. By convention, its name must end with the suffix Property. UseDependencyProperty.Registerto register it with the framework.public static readonly DependencyProperty CurrentValueProperty = DependencyProperty.Register( name: "CurrentValue", // Name of the CLR property propertyType: typeof(int), // Data type of the property ownerType: typeof(MyCustomControl), // Type of your container class typeMetadata: new PropertyMetadata(0) // Optional: Default value / callbacks ); - Create the CLR Property Wrapper
Expose a standard C# property with the exact same name as the string used during registration (
CurrentValue). Inside the get and set blocks, callGetValue()andSetValue()from the base class.Warning: Do not add extra logic inside these accessors. The XAML parser and WPF layout engine bypass these wrappers and call SetValue directly.
public int CurrentValue { get => (int)GetValue(CurrentValueProperty); set => SetValue(CurrentValueProperty, value); } - Optional: Adding Change Callbacks
If you need your control to respond immediately when the property value updates (e.g., to redraw or update text), provide a
PropertyChangedCallbackinside thePropertyMetadata.// The callback must be a static method private static void OnCurrentValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Cast 'd' back to your control instance to run instance methods if (d is MyCustomControl control) { int oldVal = (int)e.OldValue; int newVal = (int)e.NewValue; control.UpdateControlLayout(newVal); } }
using System.Windows;
using System.Windows.Controls;
namespace WpfApp.Controls
{
public class MyCustomControl : Control
{
// 1. Static constructor to override metadata (optional, typical for custom controls)
static MyCustomControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(MyCustomControl),
new FrameworkPropertyMetadata(typeof(MyCustomControl))
);
}
// 2. Register the Dependency Property Identifier
public static readonly DependencyProperty CurrentValueProperty =
DependencyProperty.Register(
name: "CurrentValue",
propertyType: typeof(int),
ownerType: typeof(MyCustomControl),
typeMetadata: new PropertyMetadata(0, OnCurrentValueChanged)
// 0 is the default value, OnCurrentValueChanged handles updates
);
// 3. Create the CLR Property Wrapper
// Keep this clean. Do not add extra logic here, as XAML can bypass it.
public int CurrentValue
{
get => (int)GetValue(CurrentValueProperty);
set => SetValue(CurrentValueProperty, value);
}
// 4. Static Property Changed Callback
// This triggers whenever the property value changes (via code or XAML binding).
private static void OnCurrentValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MyCustomControl control)
{
int oldValue = (int)e.OldValue;
int newValue = (int)e.NewValue;
// Call an instance method to handle the visual update
control.UpdateVisuals(oldValue, newValue);
}
}
// 5. Instance Method for Component Logic
private void UpdateVisuals(int oldValue, int newValue)
{
// Place your UI updating, logging, or event triggering logic here
System.Diagnostics.Debug.WriteLine($"Value changed from {oldValue} to {newValue}");
}
}
}
Summary
Dependency Properties are one of the core building blocks of WPF. They allow WPF controls to participate in powerful features such as data binding, styling, templates, animations, property inheritance, and change notifications.
Thanks