sammarcow
sammarcow

Reputation: 2956

How can I simplify the implementation of Commands in ViewModels for WPF/MVVM?

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

Upvotes: 2

Views: 2167

Answers (3)

JerKimball
JerKimball

Reputation: 16894

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

Upvotes: 4

Marc
Marc

Reputation: 13184

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...

Upvotes: 2

Metro Smurf
Metro Smurf

Reputation: 38335

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.

Upvotes: 4

Related Questions