Programming‎ > ‎WPF‎ > ‎

Simplifying ViewModels

Techniques that I use to make ViewModels simple include:
  • Automatic implementation of INotifyPropertyChanged interface (thanks to Simon Cropp's Fody:  link)
  • Automatic method to ICommand conversion using conventions (thanks to Rob Eisenberg's Calliburn Micro: link)
I don't like too verbose code. For example, this is the code taken from the main page of very popular MVVM Framework - ReactiveUI:
public class NewUserViewModel : ReactiveObject { // This is ReactiveUI's version of implementing INotifyPropertyChanged string _Password; public string Password { get { return _Password; } set { this.RaiseAndSetIfChanged(x => x.Password, value); } } string _PasswordConfirmation; public string PasswordConfirmation { get { return _PasswordConfirmation; } set { this.RaiseAndSetIfChanged(x => x.PasswordConfirmation, value); } } ICommand OkCommand { get; protected set; } public NewUserViewModel() { // Here's the interesting part - we'll combine the change notifications // for Password and PasswordConfirmation, and that will determine when // we can hit the Ok button // // canHitOk is now a stream of True's and False's var canHitOk = this.WhenAny( x => x.Password, x => x.PasswordConfirmation, (pass, confirm) => (pass.Value == confirm.Value && pass.Value.Length > 3)); // Feed this to the canExecute of the OkCommand - now the button is // bound to the two properties and will disable itself until the // Func above is true. OkCommand = new ReactiveCommand(canHitOk); } }

Frankly, this concrete example doesn't impress me at all. I can write the same code using techniques I mentioned at the beginning and it will look like this:

public class NewUserViewModel : PropertyChangedBase { public string Password { get; set; } public string PasswordConfirmation { get; set; } public bool CanOkCommand { get { return Password == PasswordConfirmation && Password.Length > 3 } } public void OkCommand { /* and this handler is here as a bonus */ } }

It behaves exactly the same (all PropertyChanged and CanExecuteChanged events will be emitted correctly).

Don't get me wrong. I like Rx very much and I'm not saying that using it is bad. It is exactly opposite. Using Rx is very helpful in many cases (of course inside ViewModels too). I just prefer to combine all available tools to resolve concrete problems. The goal is to achieve the greatest possible simplicity and readability.