2

I have noticed that I am repeating a lot of code when implementing Commands on ViewModels for a MVVM-WPF scenario. The standard implementation, as shown below, consists of a public readonly field of type ICommand, a private DelegateCommand field and a method for the execution logic. DelegateCommand gets initialized in the ICommands get-accessor.

How can this approach be condensed, considering the repetition for every command?

private DelegateCommand saveCommand;
private DelegateCommand commandClearInputFileList;
private DelegateCommand commandInputFilesDeleteSelected;

public ICommand SaveCommand {
    get {
        if (saveCommand == null) {
            saveCommand = new DelegateCommand(CommitDataBasePush);
        }
        return saveCommand;
    }
}

public ICommand CommandClearInputFileList {
    get {
        if (commandClearInputFileList == null) {
            commandClearInputFileList = new DelegateCommand(InputFilesClear);
        }
        return commandClearInputFileList;
    }
}

public ICommand CommandInputFilesDeleteSelected {
    get {
        if (commandInputFilesDeleteSelected == null) {
            commandInputFilesDeleteSelected = new DelegateCommand(InputFilesDeleteSelected);
        }
        return commandInputFilesDeleteSelected;
    }
}
Marc
  • 12,706
  • 7
  • 61
  • 97
sammarcow
  • 2,736
  • 2
  • 28
  • 56

3 Answers3

4

Personally, I'm growing fond of this style:

    private DelegateCommand saveCommand;
    public ICommand SaveCommand 
    {
        get 
        {
            return saveCommand ?? 
                (saveCommand = new DelegateCommand(CommitDataBasePush));
        }
    }

Or, using fewer lines of code:

    private DelegateCommand saveCommand;
    public ICommand SaveCommand 
        => saveCommand ?? (saveCommand = new DelegateCommand(CommitDataBasePush));
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
JerKimball
  • 16,584
  • 3
  • 43
  • 55
4

In addition to the null coalescing operator, you can use Lazy Loading:

private Lazy<DelegateCommand> _cmd = new Lazy<DelegateCommand>(() => new DelegateCommand(InputFilesClear) );

public ICommand CommandClearInputFileList { get { return _cmd.Value; } }

Personally, I've moved away from commands in favor of the conventions provided by Caliburn.Micro framework. The command above would simply be replaced by a public method.

Metro Smurf
  • 37,266
  • 20
  • 108
  • 140
  • Yeah, I like `Lazy`'s as well...in fact, whenever I'm painted into the "crap, I'm going to write a Singleton" corner, this is how I create them now. – JerKimball Jan 30 '13 at 22:52
  • 1
    Lol, personally I've moved away from Caliburn.Micro conventions and back to commands to make my ViewModels simpler. – Cameron MacFarland Jan 31 '13 at 13:44
  • @CameronMacFarland - definitely agree some of the activation / deactivation / conductor stuff can get a bit hairy and over-complicate things. On the other hand, you can also just cherry-pick bits and pieces such as the command conventions. – Metro Smurf Jan 31 '13 at 14:47
  • @MetroSmurf Agreed. By far the best feature of Caliburn.Micro is the ability to pick and choose what bits you want to use. – Cameron MacFarland Jan 31 '13 at 15:03
  • 3
    This example only works if the command execute method is static. You'd have to initialize _cmd in the constructor if it isn't. – jayint32 Jun 04 '14 at 14:23
  • @jayint32 - I'm not sure I follow why the command execute method would have to be static. Could you provide a bit more context? – Metro Smurf Jun 05 '14 at 01:18
  • 2
    @MetroSmurf Easiest way to see what I mean is just copy the example into VS and generate the method. It will be generated as static.The InputFilesClear method is being referenced in the Func in a static context because it is in a field declaration and assignment. Are you able to compile that example against an instance method? – jayint32 Jun 05 '14 at 05:18
2

You can wrap the DelegateCommand and its lazy initialization into a simple custom command class, which implements ICommand. I call it LazyCommand and its usage is as simple as this:

// Declaration
public ICommand SomeCommand { get; private set; }

// Definition
SomeCommand = new LazyCommand(ExecuteSomeCommandMethod);

The class LazyCommand looks like this:

public class LazyCommand : ICommand
{
    private readonly Lazy<DelegateCommand> _innerCommand;

    public LazyCommand(Action executeAction, Func<bool> canExecuteAction = null)
    {
        _innerCommand = canExecuteAction == null ? 
            new Lazy<DelegateCommand>(() => new DelegateCommand(executeAction)): 
            new Lazy<DelegateCommand>(() => new DelegateCommand(executeAction, canExecuteAction));
    }

    public bool CanExecute(object parameter)
    {
        return _innerCommand.Value.CanExecute();
    }

    public void Execute(object parameter)
    {
        _innerCommand.Value.Execute();
    }

    public event EventHandler CanExecuteChanged
    {
        add { _innerCommand.Value.CanExecuteChanged += value; }
        remove { _innerCommand.Value.CanExecuteChanged -= value; }
    }

    public void RaiseCanExecuteChanged()
    {
        _innerCommand.Value.RaiseCanExecuteChanged();
    }
}

Let me know if it works for you. Cheers...

Marc
  • 12,706
  • 7
  • 61
  • 97