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.

Plus, a the instantiation code is very often simple repetitive plumbing code. Why not try to automate it?

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.

I didn’t know what to do about it, until I read this article by XAML BLOG and became inspired to write a small library.

Introducing MvvmCommandWirer, available on github!

Here’s how Command wiring works with MvvmCommandWirer:

// 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);
}

So now, all the code related to a specific Command can now be located in a single contigiuous block, instead of spread throughout the ViewModel file!

This is still very much a work-in-progress, I have done very little real-world testing with it. So I would greatly appreciate any feedback on this!

For working example code, please check out the github repository.

Get MvvmCommandWirer on NuGet!

One thought on “Introducing MVVM Command Wirer

  1. Pingback: MVVM pain points: Scattered Command code | PhilChuang.com

Leave a Reply