The concept of dependency property is fascinating. I have seen a lot of confusion around it, and here is my take on it. Without further ado, let me take you to XAML, and its output.
XAML
<UserControl x:Class="Dependency_Sample.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="75" d:DesignWidth="448" FontSize="12">
<Grid x:Name="LayoutRoot">
<StackPanel>
<ItemsControl>
<TextBlock Text="No color or font set." />
</ItemsControl>
<ItemsControl Foreground="Blue" FontSize="18" >
<StackPanel>
<TextBlock Text="No color or font set." />
</StackPanel>
<TextBlock Text="Color set to Red. Font NOT set." Foreground="Red" />
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
Output

Let me ask some questions now. All set? Here we go…
1. FontSize is set to 12 at root, but not at Grid level, StackPanel or ItemsControl level. Yet, the font size for first textbox is set to 12. How?
2. ForeGround color is set to Blue for ItemsControl and FontSize is set to 18. Just below the ItemsControl, there is a StackPanel, which doesn't support any property like FontSize or ForeGround. Still the 2nd TextBlock appears to have gone 1 more level up and appears Blue with size 18.
It appears that somehow, WPF/Silverlight controls go up the stack of the Control Tree and fetch the appropriate value. But then, if that was the case, how did StackPanel not break the hierarchy. It doesn't support the FontSize and ForeGround properties, after all? As a matter of fact, if you remove FontSize=18, it will default to 12 which is set at the Root!
All of this magic happens due to dependency property. There are a few things that you need to understand about it.
A Sample dependency property
public string Header
{
get
{
return (string)GetValue(HeaderProperty);
}
set
{
SetValue(HeaderProperty, value);
}
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string),
typeof(CustomNotification), new PropertyMetadata("Header Default",
new PropertyChangedCallback(OnHeaderChanged)));
private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MessageBox.Show("Called");
d.SetValue(CustomNotification.HeaderProperty, e.NewValue);
}
Compare it to a normal property…
private int myVar;
public int MyProperty
{
get { return myVar; }
set { myVar = value; }
}
Point 1. Dependency property is not "stored" and "retrieved". It is "computed" at runtime by the WPF/Silverlight engine. Notice the usage of GetValue, SetValue. This goes on to show that there is no direct property bag from where the value is being "retrieved from" or "stored to". It is good since it reduces a lot of memory foot print by ensuring that the objects are not pre-populated with default values. Also notice the usage of HeaderProperty naming convention.
Point 2. Notice the static readonly DependencyProperty HeaderPoperty… above. This statement takes care of registering the property in such a way that now you can bind the property directly in XAML and whenever the property changes, your UI will be notified based on data binding. This is not the case with the normal property, since there is no way of notification.
Point 3. What if you have to manipulate the setter in dependency property? Should you be modifying the SetValue method directly? Well… no! Although it may work in majority of the cases, it can introduce some hard to find bugs!!! Do you remember I told you that the Framework takes care of calling SetValue and GetValue? What if the .NET code directly accesses the internal variables and sets it, instead of calling SetValue? Then in that case, although you would have written the code in SetValue, it won't be executed. Don't worry, there is an easy way out. First thing first, ensure that you never modify SetValue. What you really should do is to use a PropertyMetadata to provide a default value if required, and a callback function. Write your setter validation method in the callback method and you should be good. See the sample above.
For more information, please check the following…
http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.aspx
http://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty.aspx
http://msdn.microsoft.com/en-us/library/ms752914.aspx
Hope this helps,
Rahul
Quote of the day:
I finally figured out the only reason to be alive is to enjoy it. - Rita Mae Brown