WPF/MVVM Hack: ValueChangedEventManager

Anyone that has had extensive experience with WPF and has attempted MVVM knows it’s not perfect.  Over the years I’ve attempted many things in an attempt to find the mythical answer to all things WPF data binding.  Have I found the solution?  Not really, but I found something that makes me feel like it would be a small piece of the perfect solution.

The perfect solution to WPF data binding issues?

  1. It would be a small, nearly invisible framework, that largely works behind the scenes to keep the data and the UI in sync.
  2. Users could bind a view model to an underlying object.  Users could bind the underlying object elsewhere.  A change in either location would update the other.  Also, any other view model of the same object would also be updated.
  3. No modifications need ever be required to the “business object”.  By which I mean, my business objects should not have to implement the INotifyPropertyChanged interface.
  4. If I need to replace some portion of functionality that is exposed to the UI I should be able to do so, without requiring that I mindlessly create wrappers for everything else.
  5. WPF needs a general solution to the problem of state persistence in-between refreshes.  Example, the treeview suffers from this, for anything but the simplest of bindings where you just so happen to use an ObservableCollection.  Otherwise your left creating viewmodels that create other viewmodels that maintain selection and expansion knowledge.

So what is in this post?

I’m sure the list could be much longer, but lets move on.  So how much of this will I address today?  Just #1 and #2.

The Exposition

While working on an XNA hobby project. I started making a little level editor and decided to mostly use WPF, but kept the Windows Forms PropertyGrid for editing objects.  All the objects I’m working with are designed to be fast.  So you can forget about adding property changed events to every property.

Well, I had one of the these objects directly bound in the UI.  Not thinking about it, I modified it in the PropertyGrid.

Surprise!

To my surprise I saw the databound value update in WPF after changing it in the PropertyGrid.  I was completely stumped, I’ve never seen this happen.  There were no events in the object being modified, so no way for WPF to have been alerted to the change occurring, and yet, there it was.

There must be some invisible connection between these two objects that I’ve never heard of.  Well, there is, the ValueChangedEventManager.  It’s a Microsoft internal class that is another weak event manager used by WPF.  Why Microsoft added it?  I’m not completely sure of the intended purpose, but as it turns out, every binding statement lets the ValueChangedEventManager know what it has databound and in return the binding statement is notified by ReflectPropertyDescriptor whenever they are changed through a call to SetValue.

The FauxValueChangedEventManager!

So what does this mean?  It means that with a little bit of reflection hackery, we too can harness this power for our own.  Wouldn’t it be nice to be able to directly attach business objects to the UI when it makes sense and still get updates? Enter the FauxValueChangedEventManager:

Usage

After we modify a property on our business object, all we need to do to make sure WPF updates the binding (should one actually exist) is to do the following.

FauxValueChangedEventManager.NotifyPropertyChanged(businessObject, "PropertyName");

Further Extensions

While working on this I thought about combining it with the concept of a “DynamicObject-ViewModel”, which is just the idea that instead of specially designing a ViewModel, you could create one ViewModel that extends from DynamicObject. That way you can emit PropertyChanged events, without wrapping each property. There’s already a writeup on the concept elsewhere: Easy INotifyPropertyChanged Via DynamicObject Proxy.

However, you could extend the concept by also using the FauxValueChangedEventManager. To notify any other WPF UI that has databound itself directly to the underlying object (instead of the dynamic viewmodel). That way it too would update.