Introduction
In this article, the answer to the question posed in the title is in the name itself: Any property which is dependent on any external source to set their value is known as a dependency property.
Value can be data, which is bound to the property, or style ,which is applied on the property.
Let's go ahead and create a WPF application to understand it practically.
We all are familiar with C# CLR properties, which look something like this:
- private int myVar;
-
- public int MyProperty
- {
- get { return myVar; }
- set { myVar = value; }
- }
Dependency properties are an extension of these CLR properties.
Open your Visual Studio & create a WPF application.
Go to NuGet package manager and install Prism.wpf because we are going to follow the MVVM design pattern for the same.
Let's add one textbox, button & text-block. Textblock will display text which was entered in textbox after clicking a button.
So update MainWindow.xaml as follows:
- <Window x:Class="DependencyProperty.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Window.Resources>
- <Style x:Key="TextBlockBottomStyle" BasedOn="{StaticResource {x:Type TextBlock}}"
- TargetType="TextBlock">
- <Style.Setters>
- <Setter Property="FontSize" Value="40"/>
- <Setter Property="FontStyle" Value="Italic"/>
- </Style.Setters>
- </Style>
- <Thickness x:Key="MarginTOP">0 5 0 0</Thickness>
- </Window.Resources>
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- </Grid.RowDefinitions>
- <StackPanel Orientation="Horizontal">
- <Label x:Name="LabelUserName"
- Content="UserName:"
- VerticalAlignment="Center"
- Margin="200 0 0 0"/>
- <TextBox x:Name="TextBoxName"
- Text="{Binding UserName}"
- Height="30"
- Width="300"/>
- </StackPanel>
- <Button x:Name="ButtonSubmit"
- Margin="{StaticResource MarginTOP}"
- Content="Submit"
- Height="20"
- Width="100"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"
- Grid.Row="1"/>
- <TextBlock x:Name="TextBlockUserName"
- Text="{Binding UserName}"
- Style="{DynamicResource TextBlockBottomStyle}"
- HorizontalAlignment="Center"
- VerticalAlignment="Top"
- Grid.Row="2"/>
- </Grid>
- </Window>
Notice that we have created style inside window.resources. And we have boundd this TextBlockBottomStyle to the textblock at the end.
Here, Textblock TextBlockUserName has style property which is bound by dynamic resources.
In the same way, you can see it has Text property which is bound by the CLR property. Here, Text is your CLR property which is encapsulated by Dependency property named TextPropery inside your TextBox's control class.
Let's go ahead and create a MainWindowViewModel.cs class.
- using Prism.Mvvm;
-
- namespace DependencyProperty
- {
- public class MainWindowViewModel : BindableBase
- {
- #region Properties
- private string _userName;
-
- public string UserName
- {
- get { return _userName; }
- set => SetProperty(ref _userName, value);
- }
- #endregion
- }
- }
You also need to tell MainWindow.xaml class where the dataContext is, so update the MainWindow.XAML.cs, as follows:
- using System.Windows;
-
- namespace DependencyProperty
- {
-
-
-
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- this.DataContext = new MainWindowViewModel();
- }
- }
- }
This is what your output would look like:
Explanation
I entered Text: User Alex, which is captured by the property Text of TextBoxUserName control.
Textblock TextBlockUserName shows the same text as entered because we have bound the same CLR property: UserName to the Text property of TextBlockUserName.
Also, you can see there is a different style in which it displays text, that's because of the style we applied on TextBlockUserName.
How is this happening? The text being a normal CLR property of a control textbox or textblock, how does it act as a dependency property?
For that, we need to navigate towards the textbox's definition. As you can see there is DependencyProperty Name as TextProperty which encapsulates TextBox's Text property.
So normal CLR properties are visible as a control's element to the user & encapsulating dependency properties act as a setter to those CLR properties.
WPF uses dependency properties internally and the name of dependency property will always end with a keyword property. It's a standard convention, so they are always static and readonly; e.g. public static readonly DependencyProperty TextWrappingProperty.
- Why static?
This is because it always is available by all the controls & shared among them so it needs to be static. We don't want an object of control to access these properties at their instance.
- Why readonly?
Its value should not change after initialization.
Let's create a dependency property, which will check if text is entered in textbox or not, it will be backed by boolean CLR property.
- public static readonly DependencyProperty IsTextEnteredProperty =
- DependencyProperty.Register(
- "IsTextEntered", typeof(Boolean),
- typeof(TextBox)
- );
- public bool IsTextEntered
- {
- get { return (bool)GetValue(IsTextEnteredProperty); }
- set { SetValueIsTextEnteredProperty, value); }
- }
Now you can use IsTextEntered in TextBox and add your logic to it.
Thank you for reading this article! I hope you understood the concept of dependency properties.
Happy Coding!