Reputation: 2956
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 ICommand
s 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
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
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
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