Tuesday, December 4, 2007

DataModel-View-ViewModel

WPF changed the rules for UI best practice, but it didn't update the book.

With all the new and improved DataBinding and Command features - a new set of patterns have emerged, including a recommended pattern called DataModel-View-ViewModel (DM-V-VM).

At a conceptual level this pattern looks fantastic – but there are issues... namely it doesn’t work for non-trivial scenarios.

Rather than a boring high level rant, I'll use boring examples to explain why:

Cannot support events

The recommended approach is to use DataTemplates and Commands - but DataTempates cannot handle events, and the command system is not extensive enough (eg. doesn't support mouse clicks).

Supporting events requires using code behind; which means using at least a UserControl base class.

No Keyboard support for Standard Commands

Dan Crevier and John Gossman don't mention the standard Commands, instead opting to create their own – not because it's better practice, but it's easier to demonstrate.

Their suggested approach uses CommandParameter bindings on the buttons, which only works with OnClick (i.e when the shortcut Key is pressed "null" is passed through).

Since the InputBindings.KeyBinding.CommandParameter does not support DataBinding - supporting the keyboard (and still using commands) means we can't use CommandParameters.

UI support breaks abstraction

Say that we want to delete all the selected items from a list; this means storing a list of items in the ViewModel (since we not using CommandParameters), which we then bind from our View.

But this is purely for UI logic rather than business logic!

Complicated scenarios might need multiple properties - and since the binding is not clearly defined, it will introduce bugs.

The abstraction is now broken, so let's just move our ViewModel into the code behind.

Unit testing the UI logic now not easy

No kidding, that's why we initially moved the code into the ViewModel!

All of the real logic should be implemented in the data bound objects or by a class separate to the UI. These classes are unit testable, but the UI integration is not.

Aren't we back to where we started?

Not quite, WPF's new style allows us to develop a cleaner system than the days of WinForms and MFC - and while there's not a published best practice for it, it doesn't mean that it doesn't exist.


UI programming is hard, especially since it looks so easy.

2 comments:

Dan Lamping said...

Here's a perfectly good workaround to binding to the CommandParameter on an InputBinding:

http://www.wpfmentor.com/2009/01/how-to-add-binding-to-commandparameter.html

Luke Marshall said...

Thanks Dan!

It's a pity that it has to be a work around, but great that it's flexible enough to do.

Maybe XAML 4.0 will have better support for this.

Cheers,