Pages

Meta

Stop writing INotifyPropertyChanged, start using UpdateControls

If you use MVVM, you know all about INotifyPropertyChanged, and mostly you know that it’s a pain. Simple properties are a lot of code, but otherwise not too bad; but once you start having derived properties, it’s hard to make sure you fire all the right change events at the right time (and even harder to keep it right as you refactor).

Can’t we do things the way Knockout.JS does, with a framework that automatically discovers the dependencies for you?

And like magic, all your properties, all your logic, will start notifying the UI of changes. Between the ForView.Wrap wrapper at the top and the Independent<T> at the bottom, UpdateControls is able to automatically track all the dependencies, and triggers change events for computed properties whenever their ingredients change. This even works if a property changes which ingredients it uses.

ForView.Wrap wraps your top-level viewmodel in an internal class called DependentObject<T>. The first time a databinding asks for a property, the DependentObject<T> switches into recording mode, and then invokes your viewmodel property. Until that property returns, the DependentObject<T> takes note of every time you read the value from any Independent<T> anywhere; and whenever you do, it hooks that Independent<T>‘s change event.

Then the DependentObject<T> caches the property value and returns. Next time XAML asks for the value, it just returns it. (Its ingredients haven’t changed, so why not?) But as soon as any of the ingredients change, it clears its cache and fires PropertyChanged. There’s a lot of magic under the covers, but using it is dead simple. In principle.

As with any magic, there are some subtleties and gotchas, which I go into below. But first, some important notes about the documentation.

UpdateControls has a fair bit of documentation, including several good videos. Unfortunately, the API has changed in a couple of significant ways over time, but a lot of documentation still refers to the old APIs. So some places you see it one way, and some places you see it the other way, which is hella confusing.

The old APIs do still work (though not on every platform and not with every edition of Visual Studio), but there are easier — and more universal — ways to do things now.

Here are the two things you really need to know before you start reading the UpdateControls documentation:

Codegen vs. Independent<T>

Independent properties used to take more code than what I showed above. It was so tedious that the author even wrote a Visual Studio add-in to do the code generation for you. But now we have Independent<T>, which is enough simpler that you don’t need codegen. The old way still works (as long as you don’t have Visual Studio Express, which doesn’t support add-ins), but Independent<T> does a better job of encapsulating the boilerplate code, so IMO it’s the way to go.

Unfortunately, most of the code samples and screencasts still use the old way. You’ll see (and hear, in the videos) lots of references to Ctrl+D G, which tells the VS add-in to do its code generation. And you’ll see a lot of code like this:

By the way, that’s not a typo in the getter. You can return _firstName.Value if you like, but Independent<T> also has an implicit conversion to T, so as long as it’s not Independent<object> you can indeed just return _firstName;.

{u:Update} vs. plain old bindings

Originally, UpdateControls had a XAML markup extension ({u:Update}) that you were supposed to use in place of {Binding}. It took care of turning on dependency-recording mode whenever values were bound to the UI, so that it knew how to watch for changes and update the UI when ingredients change later.

Unfortunately, not all the XAML platforms support markup extensions. Silverlight didn’t get them until v5. Windows Phone 7 doesn’t have them; not sure about 8. WinRT doesn’t support them. {u:Update} isn’t going to cut it for those platforms. I suspect that {u:Update} also wouldn’t play well with visual designers like Blend; they’re all about the {Binding}.

So UpdateControls added ForView.Wrap(), which you can use in combination with plain old {Binding}. If the objects you expose to your XAML and your DataContexts and your Bindings are wrapped for view, you get the same magic, but without needing markup extensions.

Any time you see {u:Update} in the documentation, just mentally substitute {Binding}, and make sure the viewmodel gets wrapped with ForView.Wrap before the view sees it. For example:

If you’re starting with UpdateControls on a new project, I would imagine it’s not too hard to follow the rules and have things work well. If you’re integrating it into an existing code base, you’re more likely to run into gotchas. Here are some of the problems I ran into when trying to refactor my project to use UpdateControls.

Don’t use INotifyPropertyChanged

If your viewmodel implements INotifyPropertyChanged, UpdateControls assumes you know what you’re doing, and ForView.Wrap won’t wrap that class; instead it presents your class as-is to the view. The consequence is that the computed-property notification magic won’t work for your INPC class or anything inside it. If you implement INotifyPropertyChanged, it’s all on you.

Which means that, if you’re trying to refactor from INPC to UpdateControls, you can’t do it one property at a time. To use Independent<T>, you can’t have INotifyPropertyChanged. You’ll have to change your entire viewmodel class at once: remove INotifyPropertyChanged, add Independent<T>s for everything, all in one fell swoop.

If you do viewmodel composition — where one viewmodel exposes other viewmodels as properties (think nested panels inside a larger screen) — then you probably want to start at the top level (the whole screen), and work toward the leaves (nested panels).

Corollary: Don’t use ObservableCollection<T>

I had viewmodels that exposed collections, and nothing was happening when the collection items’ properties changed. It turns out that ObservableCollection<T> implements INotifyPropertyChanged (makes sense when you think about it; you might want to bind to its Count) — so UpdateControls just exposed the collection instance directly to the UI, without attaching any of the dependency-recording logic: not for the collection itself, and not for the items inside it, either.

So don’t use ObservableCollection<T> with UpdateControls. Use IndependentList<T> instead (it’s the UpdateControls equivalent of an observable collection). Or just a plain old List<T> if the contents aren’t going to change. Or even a LINQ query (great for filtering — as long as the filter conditions boil down to Independent<T>, changing them will automatically re-run the LINQ query). But if you start using UpdateControls, you should get rid of all your references to ObservableCollection<T>.

ForView.Wrap and dependency properties

This one may be peculiar to my code, but I had some custom dependency properties whose value was a custom class. Once I started using UpdateControls, their value wasn’t that custom class anymore; the view layer (where dependency properties live) operates on the wrapper objects, not the actual viewmodels. Since my DependencyProperty.Register call specified that the property value should be of type MyCustomClass, but the actual instance was a DependentObject<MyCustomClass>, the bindings saw a type mismatch and never set my property. To get around this, I had to change my DependencyProperty.Register call to specify object as the property’s value type. (And of course my property’s change event had to use ForView.Unwrap<T> instead of casting directly to the class type.) This probably won’t affect many people, but it’s worth noting since I burned some time trying to figure it out.

Debugging wrapper objects

If you’re in the debugger, and you’re looking at a wrapper object (from ForView.Wrap), the tooltip will show the ToString() from the wrapped class — which is often the name of the wrapped class. It can be hard to even realize that the object you’re looking at is a wrapper, and not the viewmodel itself.

It’s not hard if you know how, though. If you expand the tooltip, wrappers will have a “HasErrors” property, and not much else. That should be easy to tell apart from your actual viewmodel (which will typically have lots of properties).

If you then want to drill down to see the properties of the wrapped instance, you can expand “Non-Public Members”, then “_wrappedObject”.

Integrating with Caliburn.Micro

I tried combining both UpdateControls and Caliburn.Micro in the same project, mostly because I was already using Caliburn.Micro’s IViewAware so my viewmodels could fire animations on the view and wait for them to complete. Here’s what I learned:

Caliburn.Micro doesn’t know about UpdateControls’ wrapper classes. If you’re doing viewmodel-first (where Caliburn.Micro automatically discovers and instantiates the correct view type for you), and your DataContext is a DependentObject<PersonViewModel>, Caliburn.Micro’s conventions will probably look for a DependentObjectView or something — it doesn’t know that it’s supposed to look for a PersonView. This isn’t hard to deal with, though; Caliburn.Micro has good extensibility points for this sort of thing.

The IViewAware stuff won’t work out of the box either, because Caliburn.Micro takes the DataContext and says “does it implement IViewAware?” and of course it doesn’t, because it’s got the wrapper object, not your viewmodel. None of the lifecycle stuff (IGuardClose and the like) would work either, because it’s also based on interfaces. Again, you could hook CM’s extensibility points to make this work.

No idea how Caliburn.Micro’s {x:Name}-based binding conventions would play with UpdateControls. I didn’t get that far.

In the end, I decided not to use Caliburn.Micro for this app. I had a lot of custom UI, so the conventions weren’t much use to me; I was really only using CM for IViewAware, which would require some coding to integrate with UpdateControls. Easier to roll my own at that point.

But I’m confident you could use the two together. If anyone digs into this further and wants to share their code, drop me a line and I’ll either post it or link to you.

I’m pretty excited about UpdateControls. Yeah, I spent a lot of time here talking about the downsides and gotchas. But I wouldn’t have bothered if it didn’t show so much promise.

If you’ve used Knockout, or if you’re tired of keeping track of which calculated properties to fire PropertyChanged events for whenever something changes, you owe it to yourself to take a look at UpdateControls.

Here’s where to start:

First, look through the notes above about API drift. You’ll want to be able to mentally translate the out-of-date code samples as you see them.

Then head over to the UpdateControls documentation and read through all half-dozen or so pages; they’re short. Also take a quick look through the other sections in the sidebar (“Examples”, “Tips”, “Advanced Topics”).

Then check out the videos, which cover different material than the docs, and which dig a lot deeper. They’ll really give you an idea of what UpdateControls can do.