If you are familiar with the MVVM pattern, often used in WPF/XAML, you probably know what a viewmodel should look like. These classes get quite big pretty quickly. Considering that they are mainly just an adapter on your model, to be accessed by your view, they contain a lot of duplicate code. Wherever you read “duplicate”, there most likely exists a cleaner solution, so I’ll cut to the chase. What follows are two code samples with the same behavior. In the second sample I use a factory to minimize the required code. This approach has additional advantages as well as I’ll explain later.
Let’s make a ViewModel to edit this rubber duck! (This might sound familiar to you if you have read Head First’s great book on design patterns.)
Traditional implementation:
public class DuckViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private Duck m_duck; private bool m_canQuack; public bool CanQuack { get { return m_canQuack; } set { m_canQuack = value; RaisePropertyChanged("CanQuack"); } } private Color m_color; public Color Color { get { return m_color; } set { m_color = value; RaisePropertyChanged("Color"); } } private RelayCommand m_quackCommand; public ICommand QuackCommand { get { return m_quackCommand; } } private RelayCommand m_saveCommand; public ICommand SaveCommand { get { return m_saveCommand; } } public DuckViewModel(Duck duck) { m_duck = duck; CanQuack = duck.CanQuack; Color = duck.Color; m_quackCommand = new RelayCommand(() => Quack(), () => CanQuack()); m_saveCommand = new RelayCommand(() => Save()); } public void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyEventArgs(property)); } } public void Quack() { m_duck.Quack(); } public void CanQuack() { return m_duck.CanQuack; } public void Save() { m_duck.CanQuack = CanQuack; m_duck.Color = Color; } }
Phew, that’s a whole lot to write just for two properties and two commands isn’t it? Let’s try improving this.
Factory approach:
public enum Properties { CanQuack, Color } public enum Commands { Save, Quack } public class DuckViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private readonly NotifyPropertyFactory<Properties> m_properties; private readonly CommandFactory<Commands> m_commands; private Duck m_duck; [NotifyProperty(Properties.CanQuack)] public bool CanQuack { get { return (bool)m_properties.GetValue(Properties.CanQuack); } set { m_properties.SetValue(Properties.CanQuack, value); } } [NotifyProperty(Properties.Color)] public Color Color { get { return m_properties.GetValue(Properties.Color) as Color; } set { m_properties.SetValue(Properties.Color, value); } } public DuckViewModel(Duck duck) { m_duck = duck; CanQuack = duck.CanQuack; Color = duck.Color; m_properties = new NotifyPropertyFactory<Properties>(this, PropertyChanged); m_commands = new CommandFactory<Commands>(this); } [CommandExecute(Commands.Quack)] public void Quack() { m_duck.Quack(); } [CommandCanExecute(Commands.Quack)] public bool CanQuack() { return m_duck.CanQuack; } [CommandExecute(Commands.Save)] public void Save() { m_duck.CanQuack = CanQuack; m_duck.Color = Color; } }
There already exist dozens of other solutions to simplify (and improve) implementing INotifyPropertyChanged. One approach is to use a base class. I prefer the factory approach, following the design principle.
Favor composition over inheritance.
To remove the literals from the PropertyChanged call lambda’s can be used. Because my approach uses reflection, the literal isn’t a problem anymore, and is traded for an enum value.
Besides solving the previously mentioned problems, the factory approach has additional advantages:
- No more private field members required for the properties, just one for the factory.
- As an advantage of the factory design, the view model doesn’t need to know about concrete implementations. Behavior can be added/changed inside the factory.
- As you might have noticed, no more command members! All the commands are contained within the command factory. Yes, you can still magically bind to them, which I’ll explain in a bit!
How it works:
You might notice the similarity with my previously posted dependency property factory. I refactored the latter, and all three factories (commands, notify property and dependency property) use the same abstract base class AbstractEnumSpecifiedFactory, which already handles a lot of the required behavior by using reflection. It links MemberInfo objects to the desired attributes. Concrete implementation decide which attributes it needs, and what to do with them.
To be able to still bind to the commands I created a custom Markup Extension for XAML, allowing me to do the following.
<Button Command="{m:CommandBinding {x:Static Binding:Commands.Quack}}" Content="Quack" />
This has another additional advantage that binding is done in a safe way. The CommandBinding extension uses -you guessed it- reflection to get the correct command out of the CommandFactory in the data context.
While creating the CommandBinding extension I prepared myself to optionally create a custom general Binding extension, so that the naming conventions for dependency properties can safely be ignored, and the useless property fields can be removed.
Source code can be found in my FCL Extension library in the Whathecode.PresentationFramework assembly. The NotifyPropertyFactory is located in Whathecode.System.ComponentModel.NotifyPropertyFactory and the CommandFactory is located in Whathecode.System.Windows.Input.CommandFactory.
One thought on “ViewModel Property and Command Factory”