Every WPF/Silverlight programmer that writes it’s own business objects or custom controls either uses dependency properties or implements the INotifyPropertyChanged interface. Both have their own advantages and disadvantages:
Dependency properties:
- Full support for databinding (read and write).
- Only accessible from the thread that created the object.
- WPF/Silverlight dependant, so requires additional assemblies at runtime and requires .NET 3.0 (or later).
- Support for attached dependency properties, so you can extend other DependencyObject derived types with your class’ properties.
- Some additional plumbing necessary, which is less trivial then normal .NET properties (i.e. respond to property updated).
Normal .NET properties (with INotifyPropertyChanged support):
- Only suitable as a source in WPF databinding.
- Properties can be read and write from an arbitrary thread (of course, you need some thread synchronization to avoid problems).
- Not related to a specific .NET technology, so it can be used in any architecture.
- Additional plumbing necessary to fire the PropertyChanged event.
You might wonder which kind of property you need to use. You can use the following guidelines:
- If you expect to use to instantiate the class in XAML, then stick to dependency properties. This makes databinding a lot easier.
- If you expect to use the class also to be used outside the WPF/Silverlight environment, then .NET properties are the way to go.
Normal .NET properties can be written in a very convenient way, like:
public string FullName { get; set; }
But, if you want to support INotifyPropertyChanged, then you need at least the following code:
private string _fullName;
public string FullName
{
get { return this._fullName; }
set
{
if (this._fullName != value)
{
this._fullName = value;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("FullName"));
}
}
}
As you can see, the INotifyPropertyChanged support adds a lot of code to each property. Even worse… It is prone to errors, because you need to specify the property name as a string. These kind of properties are often copy/pasted, so beware of mistakes (it might raise issues when you are refactoring the code). I created a Visual Studio macro that generates this plumbing for me to avoid these mistakes. But still… It’s a lot of work and a good programmer avoids repeating tasks.
It would be nice if MS added a special .NET attribute or keyword to C# to generate the plumbing automatically at compile time. Unfortunately, there is no such keyword and it hasn’t been announced for the upcoming C# 4.0 release.
Update Controls
Recently, I listened to a podcast from Polymorphic Podcasts that had the appealing title “Update Controls may render INotifyPropertyChanged obsolete”. More information can be found on CodePlex. Although sceptical, I listened to the podcast and decided to take a deeper look into this technology.
The update controls is a library written by Michael L. Perry and it uses a completely different approach to track property changes. It keeps track of the inter property dependencies, so it knows which properties have to be updated when a property is changed. It uses a quite sophisticated algorithm to determine the dependencies, but this is all completely transparent to the programmer.
Unfortunately, this library also needs additional plumbing in your properties, which is even more then when implementing IPropertyChanged:
private string _fullName;
private Dependent _indFullName = new Dependent();
public string FullName
{
get { this._indFullName.OnGet(); return this._fullName; }
set { this._indFullName.OnSet(); this._fullName = value; }
}
The dependencies are tracked during the execution of the OnGet and OnSet methods. There is also a XAML markup extension that also contains the required plumbing for dependency tracking. The major advantage of this approach above the INotifyPropertyChanged and regular WPF depenency properties is that dependant properties are automatically updated.
Suppose the following example:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return this.FirstName + " " + this.LastName; } }
}
When you are using dependency properties or implement INotifyPropertyChanged then you need some kind of logic that also updates the fullname, when you change the first and/or lastname. When using the update controls, this is done automatically. The update controls know about it, because it sees that you call the FirstName and LastName properties inside the FullName getter. Quite clever…
As always, there is a catch… You need to go through the special XAML markup extension to make sure the value is updated. Normal WPF applications would use the following binding:
<TextBox Text="{Binding FirstName}"/>
<TextBox Text="{Binding LastName}"/>
<Label Text="{Binding FullName}"/>
When using updatecontrols, this doesn’t work. Although everything compiles and runs just fine, the FullName is never updated. To WPF it is an ordinary property, so it expects a PropertyChanged event and it will never receive it. When using the update controls you need to use the special XAML markup extension, like this:
<TextBox Text="{uc:Update FirstName}"/>
<TextBox Text="{uc:Update LastName}"/>
<Label Text="{uc:Update FullName}"/>
It seems like a minor change, but you need to know in your XAML code if your underlying object uses update controls or if it uses the old-style dependency properties or INotifyPropertyChanged. I consider this a major disadvantage and I have decided to stick with the WPF dependency properties and the INotifyPropertyChange interface.
The update controls might be very valuable, when you’re using a lot of properties that depend on eachother. In those special cases it might be convenient to have the automatic update functionality.
Using PostSharp to implement INotifyPropertyChanged
PostSharp is a tool that can be used to inject code. It is extensible and when you combine PostSharp with PropFu, then you can generate the PropertyChanged automatically.
[NotifyPropertyChanged]
public class Person : INotifyPropertyChanged
{
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
[OnPropertyChanged]
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
When you mark the class with the NotifyPropertyChanged attribute, then it will raise the PropertyChanged event for all public properties. You need to implement a method that will actually raise the property and mark it with the OnPropertyChanged attribute. After running PostSharp the class will be emitted like this:
[NotifyPropertyChanged]
public class Person : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return this._name; }
set
{
if (this._name != value)
{
this._name = value;
this.OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
[OnPropertyChanged]
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
When you install PostSharp it will update your Visual Studio configuration, so it will automatically invoke PostSharp at the end of each build. Of course, you can disable this and call PostSharp yourself.
I think this is a fairly elegant solution. PostSharp has a lot of additional functionality, so I suggest to take a further look at it.
Pingback: Properties and data binding | Silverlight Coder
Thanks for reviewing Update Controls. I’ve fixed one of the problems that you talk about. You no longer have to use the {u:Update} markup extension. Now you can use {Binding}. But, as always, there is a catch
As you set the DataContext of your Window, you need to wrap your object, like this:
DataContext = ForView.Wrap(myObject);
I published an update at http://updatecontrols.codeplex.com. I haven’t yet updated the updatecontrols.net site.
Could PostSharp be used to implement the plumbing for Update Controls too, like with INotify..?
Maybe we could write a plug in for PS so you can put an attribute over the independent properties..
//like this
[Independent]
public int MyInt {get;set;}