In the last few years, we’ve seen the WPF and Silverlight community embracing the MVVM methodology. As one of the early adopters of MVVM (one of my first post about the subject was late 2008), I’ve seen the pattern evolving both in the web community and with developers I’ve met in my daily life.
Today, I’d like to share with you a simple concept I try to stick to when I’m doing WPF, Silverlight or Windows Phone 7 development. It can be summarized as “Enough ViewModel is enough”.
The simple idea behind this slogan is that there ARE stuff which are view-related and SHOULD NOT be embedded in the ViewModel layer. I’ve seen too many developers going the “100% viewmodel way” which means for them absolutely no code-behind without any dispensation.
For example, I came across this code. It’s the ViewModel layer associated to a simple view where the user fills various input and has immediate feedback about the progress (like “75% of the fields are completed”). If by the way you’re interested in implementing this behavior you can check out this article I wrote on CodeProject)
The following code is simplified to the sake of the article:
public class ViewModel
{
// data field acts as the model object behind the VM layer
private Data data;
// missing code...
// public properties used by the view using databinding
public ViewModel()
{
// very simplified for this article...
this.data = new Data();
this.data.SelectedValuesChanged += new EventHandler(data_SelectedValuesChanged);
}
public void UpdateProgress()
{
// some code...
}
void data_SelectedValuesChanged(object sender, EventArgs e)
{
this.UpdateProgress();
this.Initialize();
}
public void Initialize()
{
var item = this.data.GetItem("id1");
if (item != null)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
item.SelectedValuesChanged += new EventHandler(item_SelectedValuesChanged);
foreach (var value in item.Values)
value.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
item = this.data.GetItem("id2");
if (item != null)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
item.SelectedValuesChanged += new EventHandler(item_SelectedValuesChanged);
foreach (var value in item.Values)
value.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
void item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
this.UpdateProgress();
}
void item_SelectedValuesChanged(object sender, EventArgs e)
{
this.UpdateProgress();
}
}
The idea is simple, as soon as the user changes a value in the View, we must compute the current progress. Because the ViewModel have several levels, we end-up having to register to every single PropertyChanged event which leads to cumbersome code. By the way, this code can also creates memory leaks since we register a lot of event handlers without removing them, but that’s another discussion…
Here is my way to solve this problem:
public partial class View : UserControl
{
private readonly ViewModel viewmodel;
public View()
{
InitializeComponent();
this.viewmodel = new ViewModel();
this.AddHandler(
FocusManager.LostFocusEvent,
new RoutedEventHandler(this.OnLostFocus),
true);
}
private void OnLostFocus(object sender, RoutedEventArgs e)
{
this.viewmodel.UpdateProgress();
}
}
What is wrong with this way ? The View has code-behind ? That’s not a big deal: the code is more readable, maintainable. It makes also more sense: when a view-related operation occurs (in this case, focus has changed), update the progress.
The simple message I’d like to spread is the fact that there is nothing wrong with the fact to have sometime, a little bit of code-behind in your view if that facilitates your architecture. There is no need to create a complicated infrastructure with behaviors, commands or bindings just to keep the view empty if that does not make sense.
Another great example in a real application is available in the Advanced MVVM book by Josh Smith.
Jeremy: Right on! Sometimes, the code you have in code-behind is not behavior at all, but wiring to your behavior. The only reason you need to do this at all is because we have purely declarative XAML. In other words, it would be nice to add this into your XAML directly:
Since we can’t do this, we are stuck putting it in the code-behind. BUT, I cannot stress this enough. This is not behavior. This is only wiring up behavior. The behavior can stay in the VM and you can wire it however the eff you want.
As an aside, this is something I find to be pretty great about Flex markup. You can add wiring like this directly into your view because they allow for some imperative code to be mixed within the markup… especially with data binding and events (immagine an MVVM world without commands, where you can call functions directly)
Thanks for a bit of sense this morning,
@BrianGenisio
Hi Jeremy, nice article !
I agree that the code-behind is sometimes the right place to put view-related code. However I rarely do it (except for very specific tasks unrelated to the ViewModel), mostly because code-behind is not easily reusable.
In this case it would be useful to be able to reuse this behavior in multiple views, so it would make sense to implement it as an attached behavior:
The code in my last comment didn’t show up… here it is again:
<UserControl x:Class="..."
...
bhv:FocusBehavior.LostFocusCommand="{Binding UpdateProgressCommand}">
Thomas,
Yes I’m a big fan of behaviors too. The point I want to make here is that I’m seeing to many developers pushing everything they can in a huge class they call SomethingViewModel. And I don’t think this is the goal of the methodology 🙂
You also achieve the same using reactive programming which would be just as simple but also add the power to filter exactly which events you wanted to look for.
Good point. A 100% purist approach at the expense of readable code is a poor tradeoff. But I have a different solution to the problem. I’ve adapted a dependency tracking algorithm (like the one used in Knockout.js) to the MVVM pattern. The result is Update Controls (link above). This library keeps track of dependencies so you never have to explicitly call for an update. I think you’ll find that it cleans up the code quite nicely.
It’s important to remember just why we wanted MVVM, and one of the most important reasons was for testability!
I could argue that a lot of the glue code used in the code behind, simply doesn’t need testing at the application of system level.
That enabling code is generally used to support the more complex code in the view model.
Being 100% pure in anything tends to be a prescription for closed thinking, because nothing we do is 100% right all the time, and for every situation.
Michael,
Thanks for the link I’ll check it out !
Fallon,
Completely agree with you: testability is my #1 concern. Problem is that I’m seeing to many developers doing MVVM just because someone told them to but without knowing the goal behind that…