Create Custom Dependency Property In WPF

Introduction

Before understanding this article I would recommend you read about Dependency Property

How to create a custom dependency property?

To create a new dependency property we need to follow the below procedure.

  • Declare and register dependency property
  • For registered property set value using the SetValue method and get value using the GetValue method
  • Write a method to handle change done on the dependency property

Example

We will add a dependency property called “SetBackGroundRed” to CustomButton by inheriting the Button class. To create a custom dependency property we will follow the steps that we defined previously

Declare and register dependency property

While registering dependency property we need the below parameters.

  • Name of the property: In our case it is SetBackGroundRed
  • Type of property: In our case, we will set it as Bool
  • Type of owner property: In our case, owner property will be CustomProperty
  • PropertyMetadata with Name of the method which handles change done on dependency property: in our case method which changes done on dependency property is Change BackGround.
public static readonly DependencyProperty dependencyProperty =
    DependencyProperty.Register("SetBackGroundRed", typeof(bool), typeof(CustomButton),
        new PropertyMetadata(false, new PropertyChangedCallback(ChangeBackGround)));

For registered property set value using the SetValue method and get value using the GetValue method.

SetValue and GetValue are methods defined by the DependencyObject Class.

public bool SetBackGroundRed
{
    get => (bool)GetValue(dependencyProperty);
    set => SetValue(dependencyProperty, value);
}

Write a method to handle change done on the dependency property

In the below code, we can see that we provided a method to handle changes in dependency property using DependencyObject d and DependencyPropertyChangedEventArgs like below. In the below example when the property value is set as True, we will set the background as Red else CustomButton will have the default value.

DependencyObject defines the CustomButton instance

DependencyPropertyChangedEventArgs defines the value which is set to SetBackGroundRed

private static void ChangeBackGround(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if ((bool)e.NewValue)
        (d as CustomButton).Background = Brushes.Red;
}

All code in a single file looks like below.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace DependencyPropertiesSample
{
    public class CustomButton : Button
    {
        public static readonly DependencyProperty dependencyProperty =
            DependencyProperty.Register("SetBackGroundRed", typeof(bool), typeof(CustomButton),
                new PropertyMetadata(false, new PropertyChangedCallback(ChangeBackGround)));

        public bool SetBackGroundRed
        {
            get => (bool)GetValue(dependencyProperty);
            set => SetValue(dependencyProperty, value);
        }

        private static void ChangeBackGround(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
                (d as CustomButton).Background = Brushes.Red;
        }
    }
}

On the XAML side add the below code.

<Window x:Class="DependencyPropertiesSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DependencyPropertiesSample"
        mc:Ignorable="d" SizeToContent="WidthAndHeight" WindowStyle="None"
        AllowsTransparency="True" MouseDown="Window_MouseDown" BorderBrush="Silver" BorderThickness="2"
        Title="PersonView" Height="120" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="80"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Width="400" Background="Orange">
            <Label Content="Custom Dependency Property with example" FontSize="14" Foreground="White" FontWeight="SemiBold"/>
            <Button Height="24" Width="24" Name="btnClose" HorizontalAlignment="Right" FontWeight="Bold" Cursor="Hand"
                    VerticalAlignment="Center" Content="X" Click="BtnClose_Click" Focusable="False" Background="{x:Null}" Foreground="White"/>
            <x:Code>
                <![CDATA[
                    private void BtnClose_Click(object sender, RoutedEventArgs e)
                    {
                        Close();
                    }
                    private void Window_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
                    {
                        try
                        {
                            this.DragMove();
                        }
                        catch
                        {
                        }
                    }
                ]]>
            </x:Code>
        </Grid>
        <Grid Grid.Row="1" Background="White">
            <GroupBox Header="Custom Dependency Property" Height="60">
                <local:CustomButton SetBackGroundRed="True" Width="200" Height="30" Content="Custom Button" Foreground="White"/>
            </GroupBox>                     
        </Grid>
    </Grid>
</Window>

In XAML we can see that we are handling CustomButton Background by Boolean variable SetBackGroundRed; i.e., if the value is set to True background will become Red, else Background will have the default Background color.

<local:CustomButton SetBackGroundRed="True" Width="200" Height="30" Content="Custom Button" Foreground="White" />

Below is the execution window when SetBackGroundRed=False

Execution window

Below is the execution window when SetBackGroundRed=True

Custom Button

Summary

In this article, we saw how to create a custom dependency property and how to handle the value change in the dependency property.