ViewModelBase class
Base class for ViewModels by the MVVM pattern, with several simplifications for derived classes.
Probably every WPF project following the MVVM pattern (Model–View–ViewModel) has a class called “ViewModelBase” somewhere. It serves as base class for all ViewModel classes of the application and provides an implementation of the INotifyPropertyChanged
interface in most cases. This is at least, besides the event, a protected method like “OnPropertyChanged” or “RaisePropertyChanged”.
But that alone doesn’t make the programmer’s life easier yet when there are numerous classes with equally numerous properties to be implemented, with dependencies among them (computed properties).
My implementation of this class provides the following simplifications for WPF applications:
Some ideas are taken from Steve Cadwallader who provides a thorough explanation in three articles (1, 2, 3).
Compatibility:
You can have these features at even less writing, full performance and less memory consumption with the newer Fody add-in ViewModelKit.Fody.
Example
The following sample class shows a derived class of ViewModelBase:
{
#region Data properties
// Replacing the base DisplayName property
public override string DisplayName
{
get { return FirstName + " " + LastName; }
set { }
}
// Usage of GetValue and SetValue with C# 4 (.NET 4.0, Visual Studio 2010)
public string FirstName
{
get { return GetValue<string>("FirstName"); }
set { SetValue(value, "FirstName"); }
}
// Usage of GetValue and SetValue with C# 5 (.NET 4.5, Visual Studio 2012+)
public string LastName
{
get { return GetValue<string>(); }
set { SetValue(value); }
}
// The change method is called when LastName was changed (after the value is stored
// and before the PropertyChanged event is raised)
[PropertyChangedHandler("LastName")]
private void OnLastNameChanged()
{
if (knownNames.Contains(LastName))
{
SayHelloCommand.TryExecute();
}
}
// Reformatting of a date from text input;
// Changing this property sets IsModified to true
[SetsModified]
public string Birthdate
{
get { return GetValue<string>(); }
set { SetValue(SanitizeDate(value)); }
}
// Changes with Birthdate
[NotifiesOn("Birthdate")]
public int Age
{
get
{
return (DateTime.Now - DateTime.Parse(Birthdate)).Years; // Pseudocode!
}
}
#endregion Data properties
#region Commands
// Declaration of all commands;
// SayHello depends on the current Birthdate
[NotifiesOn("Birthdate")]
public DelegateCommand SayHelloCommand { get; private set; }
// Initialisation of the commands, is called from the constructor
protected override void InitializeCommands()
{
SayHelloCommand = new DelegateCommand(OnSayHello, CanSayHello);
}
// Command handler methods
private bool CanSayHello()
{
return DateTime.Parse(Birthdate) < DateTime.Now;
}
private void OnSayHello()
{
Console.WriteLine("Hello " + DisplayName + "!");
}
#endregion Commands
}
Download
ViewModelBase.cs33.7 KiBSource code of the ViewModelBase class
Usage notes
You need the CollectionDictionary class and the DelegateCommand class to use the ViewModelBase class.
Depending on whether you are using the ViewModelBase class in a project targeting .NET 4.0 or from 4.5, you must enable or disable the CSHARP50
define at the beginning on the file. This is used to write compact code using the CallerMemberName
attribute for both environments.
Changes
IsModified
management with a predefined property, set totrue
whenever a property marked with theSetsModified
attribute is changed. Reset this in your code after loading and saving. TheDisplayName
property can be included by setting theDisplayNameSetsModified
property.ViewState
management with a dynamic object, much likeViewBag
in ASP.NET MVC. Lets you store and restore the current state of a view when navigating back and forth.- Dependent commands: Commands marked with the
NotifiesOn
attribute raise theirCanExecuteChanged
event when the specified property changes. (Requires theDelegateCommand
andCollectionDictionary
classes.) - Fix: Removed static reflection cache that may have caused memory leaks by keeping a reference to old ViewModel instances.
- Code cleanup (formatting).
Licence and terms of use
Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. (GNU All-Permissive licence)
Statistic data
- Created on 2012-07-09, updated on 2015-08-27.
- Ca. 650 lines of code, estimated development costs: 650 - 2 600 €