Ayende @ Rahien

Unnatural acts on source code

An easier way to manage INotifyPropertyChanged

If you are working with WPF or Silverlight view models, then you know that one of the more annoying things to deal with is implementing INotifyPropertyChanged to support refreshing the UI when the model is changed.

At some point, I got tried of that and wrote this:

public class Observable<T> : INotifyPropertyChanged
{
	private T value;

	public Observable()
	{
		
	}

	public Observable(T value)
	{
		this.value = value;
	}

	public T Value
	{
		get{ return value;}
		set
		{
			this.value = value;
			PropertyChanged(this, new PropertyChangedEventArgs("Value"));
		}
	}

	public static implicit operator T(Observable<T> val)
	{
		return val.value;
	}


	public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

This doesn’t seem to be very interesting, right? But it has some nice properties. Here is an example of a view model making use of this.

public class Model : IPagingInformation
{
	public Observable<bool> AllowEditing { get; set; }

	public Observable<int> NumberOfPages { get; set; }

	public Observable<int> CurrentPage { get; set; }
}

One of the nice things about the Observable class is that it is make it easy to work with the stored values. For example:

Model.AllowEditing.Value = !Model.AllowEditing;
Model.CurrentPage.Value = Model.CurrentPage +1;

In other words, you can treat the object as if it wasn’t a wrapper for reading purposes. I could make it both ways, but then I would have no way of maintaining the same instance for updates. Overall, I found the it made it quite a bit easier to deal with the task of UI updates.

Comments

Jonathon Rossi
08/08/2009 09:59 AM by
Jonathon Rossi

Any reason you are not using DependencyObject and DependencyProperty? It is a lot nicer for WPF view models.

liviu
08/08/2009 10:42 AM by
liviu

Hi, nice one.

Some might argue that for each property of an object there are extra M small objects allocated. But the advantages are clear.

Another idea would be tot store the PropertyChangedEventArgs in a static member and not to create it at each invocation:

private static PropertyChangedEventArgs args = new PropertyChangedEventArgs("Value");

Philipp Sumi
08/08/2009 10:46 AM by
Philipp Sumi

Thinking outside the box pays off I'd say - smart solution :)

Fred Hirschfeld
08/08/2009 11:12 AM by
Fred Hirschfeld

The default VS2008 WCF service proxy generator already takes care of the INotifyPropertyChanged on your model objects at least for Silverlight.

I am thinking to augment this so it will also add the IEditableObject like I think the RIA Services does.

Ayende Rahien
08/08/2009 01:11 PM by
Ayende Rahien

Liviu,

You wouldn't be able to measure that in any meaningful way

Ayende Rahien
08/08/2009 01:12 PM by
Ayende Rahien

Jonathon,

I really hate all the craft that you need to get it working

Stephen
08/08/2009 01:14 PM by
Stephen

Yea postsharp is a potential, more and more recently I've been thinking about what I think is one of the lacking areas in '.NET', and thats where we don't have really any control at compilation time (sure we can do pre-processors etc but thats not exactly simple)..

There are tons of places we end up pushing complex work to runtime that could well be evaluated once at compile time, I really think .NET needs a built in system that runs after compilation to IL, and can run transforms.. just as postsharp is allowing.

FallenGameR
08/08/2009 01:19 PM by
FallenGameR

What about validation?

In WPF it's convinient to run validation in properties. When validation fails exception is thrown and 'ValidatesOnExceptions=True' in binding allows to visually accent wrong field and show tooltip with explanation.

How do you propose to handle validation?

Ayende Rahien
08/08/2009 01:34 PM by
Ayende Rahien

Fallen,

I don't as of yet. I'll deal with that if/when I run into that scenario

FallenGameR
08/08/2009 01:49 PM by
FallenGameR

And how would you implement validation if it is needed? Extend Observable with 'void Validation( string propertyName )'?

Michael L Perry
08/08/2009 02:17 PM by
Michael L Perry

Here's an even easier way. Don't! http://updatecontrols.net

Update Controls automatically discovers dependencies among your properties and updates your WPF, Silverlight, and even Winforms controls.

The problem with INotifyPropertyChanged is not firing events. It's being the middle man. The View Model layer is hard to write because you have to respond to changes in the Data Model, update yourself, and forward events to the View. But when you use Update Controls, there is no data binding code in the View Model at all.

Mark Nijhof
08/08/2009 03:23 PM by
Mark Nijhof

How can you make the wrapper both ways?

Ayende Rahien
08/08/2009 03:23 PM by
Ayende Rahien

I don't understand the question

Mark Nijhof
08/08/2009 03:27 PM by
Mark Nijhof

Sorry, you said "you can treat the object as if it wasn’t a wrapper for reading purposes. I could make it both ways" I understand how this works for reading, but I didn't know you could do the same for writing values to the .Value property.

F.ex: AllowEditing = true would work than?

-Mark

Justin Chase
08/08/2009 04:55 PM by
Justin Chase

You might want to pick a name other than Observable <t since there actually will be an Observable <t in .net 4 which does something very different.

themechanicalbride.blogspot.com/.../...events.html>

If you haven't seen this yet you should definitely check it out, very brain bending and revelatory. My favorite quote:

"To put things in perspective it’s been 13 years since Design Patterns was published and we’ve only now realized that the Observable pattern and the Iterator pattern are actually the same pattern."

Michael Sync
08/08/2009 05:41 PM by
Michael Sync

I'm regular reader of your blog but for this one, I don't agree with you. I prefer to have the actual type (e.g. int PersonID ) instead of this (e.g. Observe <int PersonID ). I feel like it makes my Model look ugly. Sorry.

John Chapman
08/08/2009 06:23 PM by
John Chapman

First, I don't think I would ever use something like this. I don't mind the extra work, and using the wrapper classes seems like just as much extra work anyway. You've also introduced .Value all over your usages (no implicit conversion on assignment).

That being said, why did you choose to use a class instead of a struct? I would actually expect to keep value semantics versus reference semantics. It seems very odd to wrap up an integer as a class to me. You also have potential performance improvements (thought doubtful to matter in 99% of the applications out there) considering that many view model type objects contain a significant number of value types.

Ayende Rahien
08/08/2009 07:50 PM by
Ayende Rahien

Mark,

Both ways meaning implementing two way implicit conversion operators.

The problem is that it would generate different instances.

Ayende Rahien
08/08/2009 07:51 PM by
Ayende Rahien

Michael,

Make a distinction between a model and view model

Frank Quednau
08/08/2009 08:24 PM by
Frank Quednau

You wouldn't believe how annoying I find the lost instance issue with the reverse implicit operator :)

Damien Guard
08/08/2009 08:46 PM by
Damien Guard

Implicit operators can be called with null so you should put a check there to return null or you may end up with null reference errors acessing .value.

[)amien

Michael L Perry
08/09/2009 04:13 AM by
Michael L Perry

Ayende,

The distinction I draw between Model (or more precisely Data Model) and View Model is this. A Data Model is persistent. A View Model is dependent.

What you've proposed here works for the Data Model because it has storage. But it does not work for a View Model. A View Model has no storage; all of its properties are calculations that bring together properties of the Data Model.

For example:

class ContactListViewModel

{

public string Title

{

get

{

  Person selectedPerson = _navigation.SelectedPerson;

  return "Contacts - " + selectedPerson.LastName + ", " + selectedPerson.FirstName;

}

}

}

Navigation and Person both persist data (Navigation only temporarily, but Person persistently). ContactListViewModel stores nothing. It's properties are dependent on others.

Andrey Shchekin
08/09/2009 07:07 AM by
Andrey Shchekin

You can also pick Obtics ( http://obtics.codeplex.com/), and you'll get real-time updates for calculated values (including Linq). I really love real-time Linq with WPF -- it completely removes the need to think what changed when and what was affected.

Chris Donnan
08/09/2009 07:37 AM by
Chris Donnan

I have done this for our WPF based projects for ~1 year. I have been calling this PropertyModel. We have also included other presentation specific per-property metadata in our property model types.

IPropertyModel <t : INotifyPropertyChanged {

T Value

bool IsEditable

string CustomEditorName

void SignalChanged()

...etc

}

This has made many of our binding scenarios much cleaner. We have also made a series of policies that toggle propertymodel settings. This has given us generally more reuse of common screens. For example our New and Edit screens are the same. The edit screens let us flip certain IsEditable values to false and so on.

'Serial related properties' often manifest in classes like:

class X {

Foo a;

bool isADirty;

bool wasAUserEntered;

}

This initial smell + the ugly repetitive INotifyPropertyChanged business helped us to normalise our property related data into 1 PropertyModel.

PropertyModel + ViewModel + CommandModels (ala Dan Crevier) is our essential WPF model.

-Chris-

Radenko Zec
08/09/2009 09:17 AM by
Radenko Zec

Ayende nice code.

Chris Donnan how to do some additional validation on properties then?

Thanks

Ayende Rahien
08/09/2009 10:51 AM by
Ayende Rahien

Michael,

Then we don't share the same definition at all.

The model in the post is my view model.

chris Donnan
08/09/2009 03:08 PM by
chris Donnan

Radenko;

Validation is a separate concern. We have CommandModels ala this blogs.msdn.com/.../756095.aspx
Each CommandModel has a Validator on it. Each validator is essentially a Func <t,validationresult> where the result has potential messages and a bool on it. This lets us compose validations together using a CompositeValidator (list of those Funcs basically). Each command is bound to the UI, we bind all our validators to enable the commands and to show messages (eg; we put tooltips over disabled buttons with the errors etc).

That is about it.

Chris

Michael L Perry
08/09/2009 08:28 PM by
Michael L Perry

Ayende,

Fair enough. Could you demonstrate then how you would update your view model from the data model? For example, set AllowEditing when certain conditions are true?

The reason I define a view model to have no storage is because it allows you to write what AllowEditing means in just one place: the getter. If it has storage, you have to set that storage from someplace else, usually from a property changed event handler. That's seems like extra work to me. I'm curious to see how you solve that.

Thanks.

Ayende Rahien
08/09/2009 09:07 PM by
Ayende Rahien

Micahel,

In about 12 hours there is going to be a post about Conditions and Facts, take a look at this

Matt Fenner
08/10/2009 01:51 AM by
Matt Fenner

"Jonathon,

I really hate all the craft that you need to get it working"

I would argue that there is more craft here. Also Dependency Properties are implemented in a way which actually makes them perform better in bindings because the framework doesn't have to use reflection.

Comments have been closed on this topic.