MVVM pain points: Scattered Command code

This post is mostly copied from Introducing MVVM Command Wirer

Wiring up Commands in MVVM apps is painful, because you’ll often have 4 discrete blocks of code relating to a single command:

  1. The Command property on the ViewModel
  2. A Func<bool> or Predicate<T> which is referenced by Command.CanExecute
  3. An Action or Action<T> which is referenced by Command.Execute
  4. Instantiation and Initialization code which instantiates the Command and links it to the CanExecute/Execute delegates, and sets up relations to other properties.

While the first 3 blocks can be located contiguously (and thus easier to find/maintain), the Instantiation & Initialization code is often all done in the constructor, or in a class-wide initialization method.

This may be a minor annoyance to most, but it really bugs me – because I like to have all code that’s related to each other located grouped together in the source code. I don’t like having to jump back and forth inside of a many-hundreds-of-lines file – it takes a lot more concentration and effort while developing.

For example, let’s say I have a ViewModel with 2 Commands, Foo and Bar:

// 1. Command Property
public ICommand FooCommand { get; private set; }

// 2. CanExecute
private bool myCanFoo;
public bool CanFoo
{
    get { return myCanFoo; }
    set
    {
        myCanFoo = value;
        RaisePropertyChanged();
    }
}

// 3. Execute
private void Foo ()
{ if (CanFoo) Output = "Foo!"; }

// 1. Command Property
public ICommand BarCommand { get; private set; }

// 2. CanExecute
public bool CanBar (String barParam)
{ return !String.IsNullOrEmpty (barParam); }

// 3. Execute
private void Bar ()
{ if (CanBar) Output = "Bar!"; }

// ... many lines later ...

public MyViewModel ()
{
    // 4. Instantiation & Initialization for each individual ICommand
    FooCommand = new DelegateCommand (Foo, () => CanFoo);
    PropertyChanged +=
        (sender, args) =>
            if (args.PropertyName == "CanFoo")
                ((DelegateCommand) FooCommand).InvalidateCanExecuteChanged ();
    BarCommand = new DelegateCommand<String> (Bar, CanBar);
}

It’s #4 that bugs me, having the Command instantiation & initialization code located far away from the actual Command logic.

So how can we group all related Command code together? That’s what MVVM Command Wirer does.

MVVM Command Wirer

For example, the previous code can be rewritten as:

// 1. Command Property
[CommandProperty(commandType: typeof(DelegateCommand))]
public ICommand FooCommand { get; private set; }

// 4. Initialization
[CommandInitializationMethod]
private void InitializeFooCommand(DelegateCommand command)
{
    PropertyChanged +=
        (sender, args) =>
            if (args.PropertyName == "CanFoo")
                command.InvalidateCanExecuteChanged ();
}

private bool myCanFoo;
// 2. CanExecute
[CommandCanExecuteMethod]
public bool CanFoo
{
    get { return myCanFoo; }
    set
    {
        myCanFoo = value;
        RaisePropertyChanged();
    }
}

// 3. Execute
[CommandExecuteMethod]
private void Foo ()
{ if (CanFoo) Output = "Foo!"; }

// 1. Command Property
[CommandProperty(commandType: typeof(DelegateCommand<String>), parameterType: typeof(String))]
public ICommand BarCommand { get; private set; }

// 2. CanExecute
[CommandCanExecuteMethod]
public bool CanBar (String barParameter)
{ return !String.IsNullOrEmpty(barParameter); }

// 3. Execute
[CommandExecuteMethod]
private void Bar (String barParameter)
{ if (CanBar (barParameter)) Output = "Bar!"; }

// ... dozens of lines later ...

public MyViewModel ()
{
    // 4. Instantiation of ALL ICommands using CommandWirer
    CommandWirer.WireAll (this);
}

MvvmCommandWirer attributes automatically determine the Command name and wire the property, initialization, CanExecute, Execute methods together.

I know that this solution doesn’t do much in the way of reducing lines of code, but it does allow you to keep all related code grouped together, which I think does a lot for a developer’s ability to focus and keep on track.

You can try out MvvmCommandWirer on github!

Feedback Welcome

What do you think? Am I on target, or off my rocker? Can you suggest a better solution? I’m always looking for a better way!

Leave a comment or drop me a line on twitter!

One thought on “MVVM pain points: Scattered Command code

  1. Pingback: MVVM pain points | PhilChuang.com

Leave a Reply