The necessity of a ViewModel class for each Model class
November 29, 2011 7 Comments
It is well known that you need a ViewModel if you want to add property change notification or validation to a Model. But what if the Model and ViewModel classes don’t differ at all? Should you create a ViewModel class if it has the same set of properties that the Model class has? The answer is yes, absolutely. The brief reasons are separation of layers and loose coupling. But I know that these abstract terms don’t sound very convincing so I’ll describe my point of view more particularly in this post.
As an example I’ll use this data source class (which can be either a web service, or a database, or a file, whatever) and this model:
public interface IModelSource
{
SettingsModel GetSettings();
}
public class SettingsModel
{
public string DefaultPage { get; set; }
public string DownloadsFolder { get; set; }
public bool AutoStart { get; set; }
}
So we should choose which approach to use.
Just to bind the model as it is:
SettingsModel model = source.GetSettings(); this.DataContext = model;
Or to use the extra ViewModel layer and convert the model before binding:
SettingsModel model = source.GetSettings(); SettingsViewModel viewModel = ConvertModelToViewModel(model); this.DataContext = viewModel;
Let’s examine some cases and look at the differences between the approaches above.
1. Remove a property from the model class.
It happens quite often during development, this type of changes can be performed on the service side or in the database. So if to remove the AutoStart property, what will happens then?
The model-only approach
You will not be aware of the error and will not notice it until you run your application, navigate to the corresponding view and look at the Output window. There among messy messages you will see the notification about the binding error:

Also you should run your application in the Debug mode. If you start it by using the Ctrl+F5 combination, you will never find the error.
The viewmodel approach
You will be notified about the error almost immediately before you run the application. And you know: the earlier the bug is found – the easier to fix it.

2. Add a property of a complicated data type to the model class.
For example, this property of the Enum type:
NumberFormatCulture NumberFormat { get; set; }
The model-only approach
It isn’t clear how to bind this enum to the ComboBox control (I think, you will not display such programming language related values as “EnglishUS” to end users, won’t you?), so you’ll search it on Google or StackOverflow and eventually you’ll choose either a hacky solution (which will work only for the particular case) or you’ll agree to use the ViewModel (and admit wasting the time).
The viewmodel approach
Just add a few lines to the mapping configuration which can be easily bound to the ComboBox:
//Mapper.CreateMap ...
.ForMember(vm => vm.NumberFormats, option => option.UseValue(
EnumExtensions.GetValues<NumberFormatCulture>().Select(TranslateEnum)))
.ForMember(vm => vm.SelectedNumberFormat, option => option.MapFrom(
m => TranslateEnum(m.NumberFormat)))
3. Change the structure of the model class.
For example, if to change some property of the string type to the property of another model type:
public PageModel DefaultPage { get; set; }
public class PageModel
{
public string Url { get; set; }
}
The model-only approach
Again, you will not notice the error until you run the application and look at the Ouput Window (see p.1). Then you should run over all the xaml-markup in the view and correct bindings. And of course launch the application once again to assure that everything is fine after the changes.
The viewmodel approach
Just fix one line of the code in the mapping configuration:
//Mapper.CreateMap ... .ForMember(vm => vm.DefaultPage, option => option.MapFrom(m => m.DefaultPage.Url))
I must say that in this case the mapper doesn’t perform compile-time checking, but you can configure it so that it throws an exception if you try to map from the object type to the string type. And exceptions are any easier to notice and understand than debug messages in the Output window.
4. Project structure and maintenability
It isn’t a big advantage of the viewmodel approach in comparison with the above described points, but anyway, it is much better to have a good project structure when each view has a corresponding view model with the same class name prefix. You will not search which model class is bound to, for example, the SettingsView class (which model class: UserSettingsModel, ServiceSettingsModel? I don’t remember so I’ll take some time to find it out). You’ll just open the folder with view models and immediately see the corresponding SettingsViewModel class.
The most popular exuse not to create the extra layer is because it allegedly takes much time. But if to calculate the exact amount, the statement will be far from the truth.
- Add the AutoMapper library by using the NuGet package manager – 20 second (this task is performed only once)
- Create a new ViewModel class and just copypaste all of the properties of the model – 30 seconds
- Configure the mapping by using code-snippets – 5 seconds per property.
So it’ll take something about 1-2 minutes to create a ViewModel and I can’t say that it is a “huge amount of time”. And this amount is nothing in comparison with the time wasted on the above described points if to use the wrong approach. Don’t afraid to spend few minutes now, it will save many hours in the future.
