MVVM RelayCommand CanExecute
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.
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();
}
JonasN89
Updated on June 04, 2022Comments
-
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 over 10 years
.RaiseCanExecuteChanged()
is a part of Prism'sDelegateCommand
library notRelayCommand
-
Aron over 10 yearsOkay. Fair. But my point stands that its not a standard class, and the OP did not specify any libraries. :)
-
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 over 10 years@Aron I'm using MVVMLight, so I have to create an .RaiseCanExecuteChanged() myself and add this to the RelayCommand?
-
JonasN89 over 10 yearsI'm not raising the CanExecuteChanged event, so I have to implement the CanExecuteChanged and add it to my RelayCommand. I'm using MVVMLight
-
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 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 over 10 yearsMy 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 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 about 10 yearsI 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 about 10 yearsOkay, can't explain that. I have the above working. If it was helpful then please up vote :)
-
reggaeguitar about 10 yearsCould be the version of MVVM Light, not sure
-
Califf almost 10 yearsAlso See this: link
-
reggaeguitar about 9 yearsMake sure you're using the CommandWPF namespace because the RelayCommand CanExecute is broken in the Command namespace. See blog.jsinh.in/…
-
Björn Boxstart over 7 yearsThanks! Because of your answer I didn't have to look for a day ;)
-
Admin almost 6 yearsEven calling the CanExecute method directly wasn't helping. Changing the namespace made it works.
-
mins almost 4 yearsI did look for a day, and then found this answer! Thanks!