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.