views:

1448

answers:

2

So in this particular MVVM implementation I'm doing, I need several commands. I really got tired of implementing the ICommand classes one by one, so I came up with a solution, but I don't know how good it is, so the input of any WPF expert here will be greatly appreciated. And if you could provide a better solution, even better!

What I did is a single ICommand class and two delegates which take an object as a parameter, one delegate is void (for OnExecute), the other bool (for OnCanExecute). So in the constructor of my ICommand (which is called by the ViewModel class) I send the two methods, and on each ICommand method I invoke the delegates' methods.

It works really good, but I'm not sure if this is a bad way to do it, or if there's a better way. Below is the complete code, any input will be greatly appreciated, even negative, but please be constructive.

Thanks!!

ViewModel:

public class TestViewModel : DependencyObject
{
 public ICommand Command1 { get; set; }
 public ICommand Command2 { get; set; }
 public ICommand Command3 { get; set; }

 public TestViewModel()
 {
  this.Command1 = new TestCommand(ExecuteCommand1, CanExecuteCommand1);
  this.Command2 = new TestCommand(ExecuteCommand2, CanExecuteCommand2);
  this.Command3 = new TestCommand(ExecuteCommand3, CanExecuteCommand3);
 }

 public bool CanExecuteCommand1(object parameter)
 {
  return true;
 }

 public void ExecuteCommand1(object parameter)
 {
  MessageBox.Show("Executing command 1");
 }

 public bool CanExecuteCommand2(object parameter)
 {
  return true;
 }

 public void ExecuteCommand2(object parameter)
 {
  MessageBox.Show("Executing command 2");
 }

 public bool CanExecuteCommand3(object parameter)
 {
  return true;
 }

 public void ExecuteCommand3(object parameter)
 {
  MessageBox.Show("Executing command 3");
 }
}

ICommand:

public class TestCommand : ICommand
{
 public delegate void ICommandOnExecute(object parameter);
 public delegate bool ICommandOnCanExecute(object parameter);

 private ICommandOnExecute _execute;
 private ICommandOnCanExecute _canExecute;

 public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod)
 {
  _execute = onExecuteMethod;
  _canExecute = onCanExecuteMethod;
 }

 #region ICommand Members

 public event EventHandler CanExecuteChanged
 {
  add { CommandManager.RequerySuggested += value; }
  remove { CommandManager.RequerySuggested -= value; }
 }

 public bool CanExecute(object parameter)
 {
  return _canExecute.Invoke(parameter);
 }

 public void Execute(object parameter)
 {
  _execute.Invoke(parameter);
 }

 #endregion
}
+2  A: 

This is almost identical to how Karl Shifflet demonstrated a RelayCommand, where Execute fires a predetermined Action. A top-notch solution, if you ask me.

public class RelayCommand : ICommand
{
    public RelayCommand(Predicate<object> canExecute, Action<object> execute)
    {
        // ... I think you can see where this goes ...
    }
    // ... etc ...
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}

This could then be used as...

public class MyViewModel
{
    private ICommand _doSomething;
    public ICommand DoSomethingCommand
    {
        get
        {
            if (_doSomething == null)
            {
                _doSomething = new RelayCommand(
                    p => this.CanDoSomething,
                    p => this.DoSomeImportantMethod()
            }
            return _doSomething;
        }
    }
}
Jarrett Meyer
It does look similar to mine. It'd be interesting to know the pros and cons of using this. Do you have a link to the article or blog where you read this?
Carlo
I'm usins this approach since I'm working with MVVM and it works like a charm ;)
Jalfp
im using it as well, the only con i can find is that you dont have a keyboard shortcut assigned to the command. any ideas?
Aran Mulholland
@Aran The best solution I've found for assigning keyboard shortcuts to a RelayCommand is CommandReference. The only con to it is that you don't get the auto population of the shortcut in context menus and such. http://joyfulwpf.blogspot.com/2009/05/mvvm-commandreference-and-keybinding.html
dustyburwell
+2  A: 

I've just created a little example showing how to implement commands in convention over configuration style. However it requires Reflection.Emit() to be available. The supporting code may seem a little weird but once written it can be used many times.

Teaser:

public class SampleViewModel: BaseViewModelStub
{
    public string Name { get; set; }

    [UiCommand]
    public void HelloWorld()
    {
        MessageBox.Show("Hello World!");
    }

    [UiCommand]
    public void Print()
    {
        MessageBox.Show(String.Concat("Hello, ", Name, "!"), "SampleViewModel");
    }

    public bool CanPrint()
    {
        return !String.IsNullOrEmpty(Name);
    }
}

}

Boris Treukhov