Search
Winners

Win Prizes

Social Presence
Twitter Twitter LinkedIn YouTube Google

Like us on Facebook
Advertisements
Top Articles Author
Fri, 31-Oct-2014 Authors
All Time Authors
Sourav.Kayal
39750
SheoNarayan
38050
Niladri.biswas
33350

Latest members | More ...


(Statistics delayed by 5 minutes)
Ads
 Article

WPF Tutorial - Dependency Property

Abhi2434
Posted by under WPF category on for Beginner level | Views : 72683 red flag
If you found plagiarised (copied) or inappropriate content,
please let us know the original source along with your correct email id (to communicate) for further action.
Rating: 4.5 out of 5
4 vote(s)
WPF introduces a new property system which is enhanced by Dependency property. There are many improvements of Dependency Property over CLR properties. In this article I have discussed how you could create your own Dependency Property and to work with various features of it.

 Download source code for WPF Tutorial - Dependency Property



Introduction


WPF comes with a lots of new features and alternatives that the normal windows applications do not have. As we have already discussed some of the features of WPF, its time to go a bit further to introduce other new features. After reading the previous articles of this tutorial, I hope you are more or less familiar with WPF architecture, borders, Effects, Transformation, Markup extensions etc. If you don't, please go through the series of articles as labeled :

So in this article I am going to introduce you with a new property system that underlay the WPF property system. We will go further to introduce how easily you can use these properties to produce custom callbacks, create attached properties, apply animations and styles etc using the all new Dependency properties.  Finally we will discuss about Binding alternatives that were left behind in the previous article to finis it totally. I hope you will like this article as well as you did for all the tutorials that I provided.

A new Property System


Well, you must have surprised to to see this title. Yes, WPF comes with a completely new technique of defining a property of a control. The unit of the new property system is a Dependency property and the wrapper class which can create a Dependency property is called a DependencyObject. We use to register a Dependency property into the property system to ensure that the object contains the property in it and we can easily get or set the value of those properties whenever we like. We even use normal CLR property to wrap around a dependency property and use GetValue and SetValue to get and set values passed within it.

This is almost same as CLR property system. So what is the advantages of the new property system. Lets see the difference between Dependency property and CLR property.

To Work with dependency property, you must derive the class from DependencyObject as the whole observer which holds the new Property System is defined within the DependencyObject.

Difference between Dependency property and CLR property


CLR property is just a wrapper around private variables. It uses Get / Set methods to retrieve and store value of a variable into it. So to be frank with you a CLR property gives you only one block in which you can write code to invoke whenever a property is get or set. Hence CLR property system is fairly straight forward.

On the other hand, the capabilities of Dependency property system is huge. The idea of Dependency property is to compute the value of the property based on the value of other external inputs. The external inputs might be styles, themes, system properties, animations etc. So, you can say a dependency property works with most of the WPF inbuilt features that were introduced.



Advantages of Dependency Property


As a matter of fact a Dependency Property have a lots of advantages over the normal CLR properties. Lets discuss the advantages a bit before we create our own dependency property :

  1. Property Value Inheritance : By Property Value Inheritance we mean that value of a Dependency property can be overridden in the hierarchy in such a way that the value with highest precedence will be set ultimately.
  2. Data Validation : We can impose Data Validation to be triggered automatically whenever the property value is modified. 
  3. Participation in Animation : Dependency property can animate. WPF animation has lots of capabilities to change value at an interval. Defining a dependency property, you can eventually support Animation for that property.
  4. Participation in Styles : Styles are elements that defines the control. We can use Style Setters on Dependency property.
  5. Participation in Templates : Templates are elements that defines the overall structure of the element. By defining Dependency property, we can use it in templates.
  6. DataBinding : As each of the Dependency property itself invokes INotifyPropertyChanged whenever the value of the property is modified, DataBinding is supported internally. To read more about INotifyPropertyChanged, please read.
  7. CallBacks : You can have callbacks to a dependency property, so that whenever a property is changed, a callback is raised.
  8. Resources: A Dependency property can take a Resource. So in XAML, you can define a Resource for the definition of a Dependency property.
  9. Metadata overrides : You can define certain behavior of a dependency property using PropertyMetaData. Thus overriding a metadata form a derived property will not require you to redefine or reimplementing the whole property definition.
  10. Designer Support : A dependency property gets support from Visual Studio Designer. You can see all the dependency properties of a control listed in the Property Window of the Designer.

In these, some of the features are only supported by Dependency Property. Animation, Styles, Templates, Property value Inheritance etc could only be participated using Dependency property. If you use CLR property instead in such cases, the compiler will generate error.

How To define a Dependency Property


Now coming to the actual code, lets see how you could define a Dependency Property.

public static readonly DependencyProperty MyCustomProperty = DependencyProperty.Register("MyCustom", typeof(string), typeof(Window1));

public string MyCustom
{
get
{
return this.GetValue(MyCustomProperty) as string;
}
set
{
this.SetValue(MyCustomProperty, value);
}
}

In the above code, I have simply defined a Dependency property. You must have surprised why a dependency property is to be declared as static. Yes, like you even I was surprised when I first saw that. But later on after reading about Dependency property, I came to know that a dependency property is maintained in class level, so you may say Class A to have a property B. So property B will be maintained to all the objects that class A have individually. The Dependency property thus creates an observer for all those properties maintained by class A and stores it there. Thus it is important to note that a Dependency property should be maintained as  static.

The naming convention of a dependency property states that it should have the same wrapper property which is passed as the first argument. Thus in our case, the name of the Wrapper "MyCustom" which we will use in our program  should be passed as the first argument of the Register method, and also the name of the Dependency property should always be suffixed with Property to the original Wrapper key. So in our case the name of the Dependency Property is MyCustomProperty. If you dont follow this, some of the functionality will behave abnormally in your program.

It should also be noted that you should not write your logic inside the Wrapper property as it will not be called every time the property is called for. It will internally call the GetValue and SetValue itself. So if you want to write your own logic when the dependency property is fetched, there are callbacks to do them.

Defining Metadata for Properties


After defining the most simplest Dependency property ever, lets make it a little enhanced. To Add metadata for a DependencyProperty we use the object of the class PropertyMetaData. If you are inside a FrameworkElement as I am inside a UserControl or a Window, you can use FrameworkMetaData rather than PropertyMetaData. Lets see how to code :

static FrameworkPropertyMetadata propertymetadata = new FrameworkPropertyMetadata("Comes as Default", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,new PropertyChangedCallback(MyCustom_PropertyChanged),new CoerceValueCallback(MyCustom_CoerceValue),
false, UpdateSourceTrigger.PropertyChanged);



public static readonly DependencyProperty MyCustomProperty = DependencyProperty.Register("MyCustom", typeof(string), typeof(Window1),
propertymetadata, new ValidateValueCallback(MyCustom_Validate));



private static void MyCustom_PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
{
//To be called whenever the DP is changed.
MessageBox.Show(string.Format("Property changed is fired : OldValue {0} NewValue : {1}", e.OldValue, e.NewValue));
}



private static object MyCustom_CoerceValue(DependencyObject dobj, object Value)
{
//called whenever dependency property value is reevaluated. The return value is the
//latest value set to the dependency property
MessageBox.Show(string.Format("CoerceValue is fired : Value {0}", Value));
return Value;
}



private static bool MyCustom_Validate(object Value)
{
//Custom validation block which takes in the value of DP
//Returns true / false based on success / failure of the validation
MessageBox.Show(string.Format("DataValidation is Fired : Value {0}", Value));
return true;
}


public string MyCustom
{
get
{
return this.GetValue(MyCustomProperty) as string;
}
set
{
this.SetValue(MyCustomProperty, value);
}
}
 

So this is little more elaborate. We define a FrameworkMetaData, where we have specified the DefaultValue for the Dependency property as "Comes as Default", so if we dont reset the value of the DependencyProperty, the object will have this value as default.  The FrameworkPropertyMetaDataOption gives you a chance to evaluate the various metadata options for the dependency property. Lets see the various options for the enumeration.

  • AffectsMeasure : Invokes AffectsMeasure for the Layout element where the object is placed.
  • AffectsArrange : Invokes AffectsArrange for the layout element.
  • AffectsParentMeasure : Invokes AffectsMeasure for the parent.
  • AffectsParentArrange : Invokes AffectsArrange for the parent control.
  • AffectsRender : Rerender the control when the value is modified.
  • NotDataBindable : Databinding could be disabled.
  • BindsTwoWayByDefault : By default databinding will be OneWay. If you want your property to have a TwoWay default binding, you can use this.
  • Inherits : It ensures that the child control to inherit value from its base.

You can use more than one option using | separation as we do for flags.

The PropertyChangedCallback is called when the property value is changed. So it will be called after the actual value is modified already. The CoerceValue is called before the actual value is modified. That means after the CoerceValue is called the value that we return from it will be assigned to the property. The validation block will be called before CoerceValue, so this event ensures if the value passed in to the property is valid or not. Depending on the validity, you need to return true or false. If the value is false, the runtime generates an error.

So in the above application after you run the code, the MessageBox comes for the following:

ValidateCallback : You need to put logic to validate the incoming data as Value argument. True makes it to take the value, false will throw the error.

CoerceValue : Can modify or change the value depending on the value passed as argument. It also receives DependencyObject as argument. You can invoke CoerceValueCallback using CoerceValue method associated with DependencyProperty.

PropertyChanged : This is the final Messagebox that you see, which will be called after the value is fully modified. You can get the OldValue and NewValue from the DependencyPropertyChangedEventArgs.


Note on CollectionType Dependency Property


CollectionType dependency property are when you want to hold a collection of DependencyObject into a collection. We often require this in our project. In general when you create a dependency object and pass the default value into it, the value will not be the default value for each instance of the object you create. Rather it will be the initial value for the Dependency property for the type it is registered with. Thus if you want to create a collection of Dependency object and want your object to have its own default value, you need to assign this value to each individual item of the dependency collection rather than defining using Metadata definition.

For instance :

public static readonly DependencyPropertyKey ObserverPropertyKey = DependencyProperty.RegisterReadOnly("Observer", typeof(ObservableCollection<Button>), typeof(MyCustomUC),new FrameworkPropertyMetadata(new ObservableCollection<Button>()));



public static readonly DependencyProperty ObserverProperty = ObserverPropertyKey.DependencyProperty;



public ObservableCollection<Button> Observer
{
get
{
return (ObservableCollection<Button>)GetValue(ObserverProperty);
}
}

In the above code you can see we declare a DependencyPropertyKey using the RegisterReadonly method. The ObservableCollection is actually a collection of Button which is eventually a DependencyObject.

Now if you use this collection, you will see that when you create object of the Usercontrol, each of them refers to the same Dependency Property rather than having its own dependency property. As by definition each dependencyproperty allocates memory using its type, so if object 2 creates a new instance of DependencyProperty, it will overwrite the Object 1 collection. Hence the object will act as a Singleton class.  To overcome with this situation, you need to reset the collection with a new instance whenever a new object of the class is created. As the property is readonly you need to use SetValue to crate the new Instance using DependencyPropertyKey.

 public MyCustomUC()
{
InitializeComponent();
SetValue(ObserverPropertyKey, new ObservableCollection<Button>());
}

 So for each instance the collection will reset and hence you will see unique collection for each UserControl created.

PropertyValue Inheritence


DependencyProperty supports Property Value inheritance. By the definition, after you create a DependencyObject for you, you can easily inherit a DependencyProperty to all its child controls using AddOwner method associated to the DependencyProperty.

Each of DependencyProperty has AddOwner method, which creates a link to another DependencyProperty that is already defined. Say you have a DependencyObject A, which has a property called Width. You want the value of the DependencyObject B to inherit the value of A.

public class A :DependencyObject
{
public static readonly DependencyProperty HeightProperty = DependencyProperty.Register("Height", typeof(int), typeof(A),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));



public int Height
{
get
{
return (int)GetValue(HeightProperty);
}
set
{
SetValue(HeightProperty, value);
}
}



public B BObject { get; set; }
}



public class B : DependencyObject
{
public static readonly DependencyProperty HeightProperty;

static B()
{
HeightProperty = A.HeightProperty.AddOwner(typeof(B), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.Inherits));
}


public int Height
{
get
{
return (int)GetValue(HeightProperty);
}
set
{
SetValue(HeightProperty, value);
}
}
}

In the above code you can see, the class B inherits the DependencyProperty Height using AddOwner without re declaring the same in the class. Thus when A is declared, if you specify the height of A, it will automatically be transferred to the inherited child object B.

This is same as normal objects. When you specify the Foreground of a Window, it will automatically inherit to all the child elements, hence the Foreground of each controls will behave the same.

Update:

Even though PropertyValueInhertence is there for any dependency property, it will actually work for AttachedProperties. I came to know that Property Value Inhertance only works when the property is taken as attached. If you set the Default Value for the Attached property and also set FrameworkMetaData.Inherits, the property value will be inherited from Parent to Child automatically and also gives the chance for the Children to modify the content. Check MSDN for more details. So, the example that I put above is not proper for Property Value Inheritence, but you can easily create one to see after you read the next section.

Attached Properties


Attached property is another interesting concept. Attached property enables you to attach a property to an object that is outside the object altogether making it to define value for it using that object. Seems a little confused huh? Yes, lets give an example.

Say you have declared a DockPanel, inside which you want your controls to appear. Now DockPanel registers an AttachedProperty.

public static readonly DependencyProperty DockProperty = DependencyProperty.RegisterAttached("Dock", typeof(Dock), typeof(DockPanel), new FrameworkPropertyMetadata(Dock.Left, new PropertyChangedCallback(DockPanel.OnDockChanged)), new ValidateValueCallback(DockPanel.IsValidDock));
You can see, the DockProperty is defined inside the DockPanel as Attached. We use RegisterAttached method to register attached DependencyProperty. Thus any UIElement children to the DockPanel will get the Dock property attached to it and hence it can define its value which automatically propagates to the DockPanel.

Lets declare a Attached DependencyProperty:

public static readonly DependencyProperty IsValuePassedProperty = DependencyProperty.RegisterAttached("IsValuePassed", typeof(bool), typeof(Window1),
new FrameworkPropertyMetadata(new PropertyChangedCallback(IsValuePassed_Changed)));



public static void SetIsValuePassed(DependencyObject obj, bool value)
{
obj.SetValue(IsValuePassedProperty, value);
}


public static bool GetIsValuePassed(DependencyObject obj)
{
return (bool)obj.GetValue(IsValuePassedProperty);
}

Here I have declared a DependencyObject that holds a value IsValuePassed. The object is bound to Window1, so you can pass a value to Window1 from any UIElement.

So in my code, the UserControl can pass the value of the property to the Window.

  <local:MyCustomUC x:Name="ucust" Grid.Row="0" local:Window1.IsValuePassed="true"/>

You can see above the IsValuePassed can be set from an external UserControl, and the same will be passed to the actual window.

As you can see I have added two static method to individually Set or Get values from the object. This would be used from the Code to ensure we pass the value from code from appropriate objects.

Say you add a button and want to pass values from code, in such cases the static method will help.

private void Button_Click(object sender, RoutedEventArgs e)
{
Window1.SetIsValuePassed(this, !(bool)this.GetValue(IsValuePassedProperty));
}

In the similar way as DockPanel Defines SetDock method.


Conclusion


To conclude, DependencyProperty is one of the most important and interesting concept that you must know before you work with WPF. There are certain situations, where you would want to declare a DependencyProperty. From this article I have basically visited each section of the DependencyProperty that you can work. I hope this one has helped you.

Thank you for reading. Looking forward of your feedback.

Page copy protected against web site content infringement by Copyscape
About the Author

Abhi2434

Full Name: Abhishek Sur
Member Level: Silver
Member Status: Member,Microsoft_MVP,MVP
Member Since: 12/2/2009 4:19:08 AM
Country: India
www.abhisheksur.com
http://www.abhisheksur.com

Working for last 2 and 1/2 years in .NET environment with profound knowledge on basics of most of the topics on it.
Login to vote for this post.
Found interesting? Add this to:


Comments or Responses

Posted by: Chvrsri on: 12/23/2010 | Points: 25

Nice Description of Dependency Property !!!

Login to post response

Comment using Facebook(Author doesn't get notification)