views:

125

answers:

2

Hi,

in my WPF UI, I use RoutedCommands that I refer to in my xaml via the following code:

Command="viewModel:MessageListViewModel.DeleteMessagesCommand"

I don't like this static link to my ViewModel class,I think this is not as nice as creating a custom ICommand implementation and use a syntax like the following

Command="{Binding DeleteMessagesCommand}"

Having created one, I notice one major drawback of what I've done: RoutedCommands utilize the CommandManager and (in some way that is completely opaque to me) fire the CommandManager.RequerySuggested event, so that their CanExecute Method is requeried automatically. As for my custom implementation, CanExecute is only fired once at startup and never again after that.

Does anybody have an elegant solution for this?

+1  A: 

Just implement the CanExecuteChanged event as follows:

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

When you assign the command to a control, it subscribes to the CanExecuteChanged event. If you "redirect" it to the CommandManager.RequerySuggested event, the control will be notified whenever CommandManager.RequerySuggested is triggered.

Thomas Levesque
Thanks a bunch for this great and concise reply! Works like a charm. Do you, by any chance, know when and why RequerySuggested is fired?
Sebastian Edelmeier
Not exactly, but I seems to happen pretty often...
Thomas Levesque
OK, thanks a lot again!
Sebastian Edelmeier
A: 

I very much prefer the DelegateCommand implementation of Prism for viewmodel binding (http://msdn.microsoft.com/en-us/library/ff654132.aspx). You can invoke CanExecute() on every command invoker by calling RaiseCanExecuteChanged on it.

Simple usage example:

public class ViewModel
{
   public ViewModel()
   {
      Command = new DelegateCommand<object>(x => CommandAction(), x => CanCommandAction());
   }

   bool state;

   public void ChangeState(bool value)
   {
      state = value;
      Command.RaiseCanExecuteChanged();
   }

   public DelegateCommand<object> Command {get; private set;}

   private void CommandAction()
   {
      //do smthn
   }

   private bool CanCommandAction() { return true == state; }
}

//and binding as usual
Command="{Binding Command}"
MrDosu
Thanks for the idea, but - as we have learned - "with great power comes great responsibility"...
Sebastian Edelmeier
Sorry, pressed Enter too soon. What I mean is : While giving me the chance to, it also forces me to do it in order to get notified.
Sebastian Edelmeier