Automatic generation of View-Model – first attempt

I recently found myself writing the same code again and again. As can be guessed, I’m writing a WPF application based on MVVM architecture. In order to avoid writing the same code again I am trying to generate the View-Model automatically using Castle Dynamic Proxy.

Simplest scenario – forwarding calls to model

This is probably the simplest case we encounter. This is so simple we are tempted to bind the view directly to the model.

Naive implementation

public class Model
{
public object Prop { get; set; }
}

public class ViewModel
{
private readonly Model model;

public ViewModel(Model model)
{
this.model = model;
}

public object Prop
{
get { return model.Prop; }
set { model.Prop = value; }
}
}

The generated alternative

So, what we’d like to achieve is skipping the forwarding implementation. The View-Model can look like:

public abstract class ViewModel
{
public abstract object Prop { get; set; }
}

So far, it’s very simple 🙂 Let’s see how it’s being used with the Model:

[Test]
public void Generate_SetPropertyValue_ModelPropertyUpdated()
{
var viewModelGenerator = new ViewModelGenerator();
var model = new Model();

ViewModel generatedViewModel = viewModelGenerator.Generate<ViewModel>(model);

object valueToAssign = new object();
generatedViewModel.Prop = valueToAssign;

Assert.That(model.Prop, Is.SameAs(valueToAssign));
}

This example shows that we’ve created a View-Model based on a Model instance, simulated a call to a property setter and the new value automatically reflected the Model. That was simple, wasn’t it?

Next scenario – Implementing INotifyPropertyChanged

This is a very common scenario, which has a very common implementation. It’s so common I’ll skip the naive implementation and jump to the generated version directly:

The generated alternative

public abstract class ViewModel : INotifyPropertyChanged
{
public abstract object Prop { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}

[
Test]
public void Generate_SetPropertyValue_PropertyChangedRaised()
{
var viewModelGenerator = new ViewModelGenerator();
var model = new Model();
ViewModel generatedViewModel = viewModelGenerator.Generate<ViewModel>(model);

bool wasRaised = false;
generatedViewModel.PropertyChanged += (sender, args) => wasRaised =
true;

generatedViewModel.Prop =
new object();

Assert.That(wasRaised, Is.True);
}

In this case we’ve generated a View-Model that implements INotifyPropertyChanged. We had to do nothing but declare the View-Model implements INotifyPropertyChanged. Whenever a property value is changed the event will be raised with the property name.

Last scenario – Implementing IDataErrorInfo

This case is trivial too so I’ll skip again the naive solution.

The generated alternative

First we’ll take a look at the format of the abstract View-Model and the validation declaration:

public abstract class ViewModel : IDataErrorInfo
{
public abstract string this[string columnName] { get; }
public abstract string Error { get; }

[
Validation(typeof(DummyValidator))]
public abstract object Prop { get; set; }
}

public class DummyValidator : IValidator
{
public string Validate(object value)
{
return "error";
}
}

The view model is now implementing the IDataErrorInfo interface. The interfaces require implementation of indexer that maps from property to error message. The automatic View-Model generation should take care of it. In order to declare the required validations we’ll use the Validation attribute. The attribute defines which validator to use on the property. The validation result will be mapped to the property name.
For example:

[Test]
public void Generate_SetInvalidPropertyValue_PropertyErrorIsCorrect()
{
var viewModelGenerator = new ViewModelGenerator();
var model = new Model();

ViewModel generatedViewModel = viewModelGenerator.Generate<ViewModel>(model);

generatedViewModel.Prop =
new object();

Assert.That(generatedViewModel["Prop"], Is.EqualTo("error"));
}

Conclusion

MVVM is used many times in common scenarios. The code is usually a template which we can generate dynamically. This way the code duplication will be drastically reduced and allow uniform implementation.
The examples here were simplified but the concept should be clear. There’s much more work on the framework in order to cover more real life scenarios, soon to come 🙂 I’ll upload the framework source code to CodePlex before the next post.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s