Simple MVVM Walkthrough – Refactored

Posted by Sean Feldman on ASP.net Weblogs See other posts from ASP.net Weblogs or by Sean Feldman
Published on Wed, 12 Jan 2011 07:07:00 GMT Indexed on 2011/01/12 7:54 UTC
Read the original article Hit count: 322

Filed under:

JR has put together a good introduction post into MVVM pattern. I love kick start examples that serve the purpose well. And even more than that I love examples that also can pass the real world projects check. So I took the sample code and refactored it slightly for a few aspects that a lot of developers might raise a brow.

Michael has mentioned model (entity) visibility from view. I agree on that. A few other items that don’t settle are using property names as string (magical strings) and Saver class internal casting of a parameter (custom code for each Saver command).

Fixing a property names usage is a straight forward exercise – leverage expressions. Something simple like this would do the initial job:

class PropertyOf<T>
  {
    public static string Resolve(Expression<Func<T, object>> expression)
    {
      var member = expression.Body as MemberExpression;
      return member.Member.Name;
    }
  }

With this, refactoring of properties names becomes an easy task, with confidence that an old property name string will not get left behind. An updated Invoice would look like this:

public class Invoice : INotifyPropertyChanged
  {
    private int id;
    private string receiver;

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }

    public int Id
    {
      get { return id; }
      set
      {
        if (id != value)
        {
          id = value;
          OnPropertyChanged(PropertyOf<Invoice>.Resolve(x => x.Id));
        }
      }
    }

    public string Receiver
    {
      get { return receiver; }
      set
      {
        receiver = value;
        OnPropertyChanged(PropertyOf<Invoice>.Resolve(x => x.Receiver));
      }
    }
  }

For the saver, I decided to change it a little so now it becomes a “view-model agnostic” command, one that can be used for multiple commands/view-models. Updated Saver code now accepts an action at construction time and executes that action. No more black magic Smile

  internal class Command : ICommand
  {
    private readonly Action executeAction;

    public Command(Action executeAction)
    {
      this.executeAction = executeAction;
    }

    public bool CanExecute(object parameter)
    {
      return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
      // no more black magic
      executeAction();
    }
  }

Change in InvoiceViewModel is instantiation of Saver command and execution action for the specific command.

 public ICommand SaveCommand
    {
      get
      {
        if (saveCommand == null)
          saveCommand = new Command(ExecuteAction);
        return saveCommand;
      }
      set { saveCommand = value; }
    }

    private void ExecuteAction()
    {
      DisplayMessage = string.Format("Thanks for creating invoice: {0} {1}", Invoice.Id, Invoice.Receiver);
    }

This way internal knowledge of InvoiceViewModel remains in InvoiceViewModel and Command (ex-Saver) is view-model agnostic.

Now the sample is not only a good introduction, but also has some practicality in it. My 5 cents on the subject.

Sample code MvvmSimple2.zip

© ASP.net Weblogs or respective owner

Related posts about wpf