MVVM RelayCommand CanExecute

19,270

Solution 1

For some reason you have to do the following:

public RelayCommand RedoCommand{
     get;
     set;
}

you can also put private before set optional, depending on your access level. Then you do

RedoCommand = new RelayCommand(() => undoRedoController.Redo(), () => undoRedoController.CanRedo());

Now your able to call RedoCommand.RaiseCanExecuteChanged(); And everything works.

Solution 2

There has been a hiatus with MVVMLight due to the fact that after the .NET 4.5 update the CommandManager no longer fires the can execute check. This has since been solved. Instead of including the GalaSoft.MvvmLight.Command namespace you should use the GalaSoft.MvvmLight.CommandWpf namespace. The RelayCommand defined in that namespace is still checking the CanExecute function that you pass to the command.

Took me about a day to find out what the hell was going wrong in my application. I hope this will help some of you.

Here is a blog post by the developer explanining why this is necessary.

Solution 3

If you are using an unpatched .net 4.5. Microsoft broke the .CanExecute event.

http://connect.microsoft.com/VisualStudio/feedback/details/753666/net-4-0-application-commands-canexecute-not-updating-in-4-5

If you are using the RelayCommand from http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030 and are not raising the CanExecuteChanged event when redoStack changes.

Solution 4

(Answering from a Silverlight perspective so assuming this will help you.)

Are you doing a RedoCommand.RaiseCanExecuteChanged() anywhere? Once whatever condition you are monitoring changes, you'll need to raise this command manually.

EDIT

Since you are using MVVM Light.. Heres sample code:

RedoCommand = new RelayCommand(undoRedoController.Redo,undoRedoController.CanRedo);

   public bool CanRedo()
    {
        redoStack.Count();
        redoStack.Any();
        return redoStack.Any();
    }

    public void Redo()
    {
        if (redoStack.Count() <= 0) throw new InvalidOperationException();
        IUndoRedoCommand command = redoStack.Pop();
        undoStack.Push(command);
        command.Execute();

        // At this point, your stacks have changed; that is, the stacks
        // may or may not contain items. Thus, raise the commands CanExecute part
        // which will in turn enable/disable the commands based on the functions
        // return value

        RedoCommand.RaiseCanExecuteChanged();

        // assuming you could possibly have an UndoCommand somewhere
        UndoCommand.RaiseCanExecuteChanged();
    }
Share:
19,270
JonasN89
Author by

JonasN89

Updated on June 04, 2022

Comments

  • JonasN89
    JonasN89 about 2 years

    I'm implementing an RelayCommand with an execute and an canExecute part. The RelayCommand works when it is without the canExecute part, however when I add the canExecute part, the command locks the button. The RelayCommand only checks whether or not the button can be executed as long as the CanExecute part is true. Once the canExecute part becomes false, the button can no longer be clicked, even if it is supposed to. How do I make sure that every time I click on the button it controls whether or not it can be executed, and doesn't lock it forever, once it cannot be executed?

    RedoCommand = new RelayCommand(undoRedoController.Redo,undoRedoController.CanRedo);
    
       public bool CanRedo()
        {
            redoStack.Count();
            redoStack.Any();
            return redoStack.Any();
        }
    
        public void Redo()
        {
            if (redoStack.Count() <= 0) throw new InvalidOperationException();
            IUndoRedoCommand command = redoStack.Pop();
            undoStack.Push(command);
            command.Execute();
        }
    
    
     public class UndoRedoController
    {
        private static UndoRedoController controller = new UndoRedoController();
    
        private readonly Stack<IUndoRedoCommand> undoStack = new Stack<IUndoRedoCommand>();
        private readonly Stack<IUndoRedoCommand> redoStack = new Stack<IUndoRedoCommand>();
    
        private UndoRedoController() { }
    
        public static UndoRedoController GetInstance() { return controller; }
    
  • Aron
    Aron over 10 years
    .RaiseCanExecuteChanged() is a part of Prism's DelegateCommand library not RelayCommand
  • Aron
    Aron over 10 years
    Okay. Fair. But my point stands that its not a standard class, and the OP did not specify any libraries. :)
  • JonasN89
    JonasN89 over 10 years
    @tsiorn No I'm not doing an RedoCommandRaiseCanExecuteChanged(), is this an function I have to implement myself and if so how?
  • JonasN89
    JonasN89 over 10 years
    @Aron I'm using MVVMLight, so I have to create an .RaiseCanExecuteChanged() myself and add this to the RelayCommand?
  • JonasN89
    JonasN89 over 10 years
    I'm not raising the CanExecuteChanged event, so I have to implement the CanExecuteChanged and add it to my RelayCommand. I'm using MVVMLight
  • tsiorn
    tsiorn over 10 years
    @JonasN89 You do not need to implement it. When you call RaiseCanExecuteChanged() method on your RelayCommand, your CanExecute method (CanRedo) will be invoked. You should call RaiseCanExecuteChanged() whenever you add or remove from your redo stack you are maintaining.
  • JonasN89
    JonasN89 over 10 years
    @tsiorn Probably didn't make this clear, but the part where I create the RelayCommand is in a different class then where I create the voids for Redo and CanRedo. So I can't find the UndoCommand there. And is there some library I have to add to get the RaisedCanExecuteChanged() part, because so far it does not come up.
  • tsiorn
    tsiorn over 10 years
    My first thought is that the class that exposes the undo/redo command should be the one to provide their implementation as well... keeping it all self contained. (sorry if im not understanding.) Can you verify that your RelayCommand is GalaSoft.MvvmLight.Command.RelayCommand? (At least that's the way the Silverlight library is - my original caveat with my answer :D)
  • JonasN89
    JonasN89 over 10 years
    @tsiorn I'am using the GalasoftMVVM.Light.Command library. The problem is that if I keep it in the class where the undo/redo part is it, does not know the RedoCommand, because I assign the RedoCommand in a different class. So I've made the RedoCommand an public static, so now i'm capable of calling it from this class, but I can't call the RaiseCanExecuteChanged. The system doesn't recognize this.
  • reggaeguitar
    reggaeguitar about 10 years
    I get a compiler error when trying that example. If one removes the "() =>" in the RelayCommand ctor and the parens after the method names, it works fine
  • JTIM
    JTIM about 10 years
    Okay, can't explain that. I have the above working. If it was helpful then please up vote :)
  • reggaeguitar
    reggaeguitar about 10 years
    Could be the version of MVVM Light, not sure
  • Califf
    Califf almost 10 years
    Also See this: link
  • reggaeguitar
    reggaeguitar about 9 years
    Make sure you're using the CommandWPF namespace because the RelayCommand CanExecute is broken in the Command namespace. See blog.jsinh.in/…
  • Björn Boxstart
    Björn Boxstart over 7 years
    Thanks! Because of your answer I didn't have to look for a day ;)
  • Admin
    Admin almost 6 years
    Even calling the CanExecute method directly wasn't helping. Changing the namespace made it works.
  • mins
    mins almost 4 years
    I did look for a day, and then found this answer! Thanks!