What is the actual task of CanExecuteChanged and CommandManager.RequerySuggested? - wpf

I got the following code from Josh Smith's MVVM tutorial.
Can anyone provide a quick explanation of what this code actually does?
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
I can't understand two things:
what does the CanExecuteChanged event do?
what does the CommandManager.RequerySuggested do?
The above code is from the RelayCommand Class from here.

CanExecuteChanged notifies any command sources (like a Button or MenuItem) that are bound to that ICommand that the value returned by CanExecute has changed. Command sources care about this because they generally need to update their status accordingly (eg. a Button will disable itself if CanExecute() returns false).
The CommandManager.RequerySuggested event is raised whenever the CommandManager thinks that something has changed that will affect the ability of commands to execute. This might be a change of focus, for example. Turns out that this event fires a lot.
So, in essence, what this bit of code does is ensure that whenever the command manager thinks a command's ability to execute has changed, the command will raise CanExecuteChanged even if it hasn't actually changed.
I actually dislike this approach to implementing ICommand.CanExecuteChanged - it feels lazy and isn't entirely reliable. I prefer a much more fine-grained approach where the command exposes a method (eg. RaiseCanExecuteChanged()) you can call to raise CanExecuteChanged, then you call this at the appropriate times from your view model.
For example, if you have a command that deletes the currently selected customer, it would have a CanExecute() handler that returns true only if there is a customer selected. You would therefore call RaiseCanExecuteChanged whenever the selected customer changes.

RoutedCommands can automatically notify if their CanExecute has changed, since we are implementing ICommand here, which the WPF system doesn't know about, we wire them to CommandManager's RequerySuggested event.
Now this event is called quite often by the WPF system when the focus changes, any control is edited etc. Hence in turn CanExecuteChanged is raised. As your button is listening to this event it will reinvoke CanExecute to know the latest status.
Here is an article that might be of interest.

Related

In what scenarios might ICommand CanExecute not update?

I've been using Josh Smith's implementation of RelayCommand in a couple of large projects for some years now. However today I've come across a scenario where the CanExecute on one of my commands isn't refreshing. I'm at a loss as to what's causing it - the view-model isn't doing anything that I haven't done dozens of times already.
The VM's constructor creates a couple of commands. The first one is a "start" command:-
StartCommand = new RelayCommand(o => StartAsync(), o => true);
The StartAsync() method looks like this:-
private async void StartAsync()
{
IsRunning = true;
await Task.Run(() => SomeLongRunningProcess(); }
IsRunning = false;
}
There is also a "save" command:-
SaveCommand = new RelayCommand(o => Save(), o => !IsRunning);
('IsRunning' is a bog-standard property, implementing INotifyPropertyChanged. As well as being used for the "CanExecute" delegate, it's also bound to the IsEnabled property of a few controls in the view to enable/disable them).
When I click my "Start" button (bound to 'StartCommand'), the "Save" button is correctly disabled. The b/g process runs to completion, then IsRunning is set to false, but this doesn't trigger the "Save" button to become enabled. It only enables if I click somewhere on my view.
(The controls whose IsEnabled property is bound to the VM IsRunning property do enable and disable correctly, by the way).
I've come across a few SO articles about this, but nothing really explains why this happens. My workaround was to bind the button's IsEnabled property to 'IsRunning', but it's frustrating that this particular view refused to play ball. Any thoughts on what might be causing this? Common sense says it's something specific to this view/VM, but I'm stumped (and I'm not going to post the code here - there's too much of it).
Yes, because the version of RelayCommand you're using is depending on CommandManager.RequerySuggested event and it's not accurate.
Its documentation states that
Occurs when the CommandManager detects conditions that might change
the ability of a command to execute.
Basically it guesses all the possible events where your data could be changed. It can never know when your ViewModel/Model is changed. It isn't listening for the property change notifications.
If you want to react immediately without waiting for CommandManager to guess, you need to fire the ICommand.CanExecuteChanged manually yourself when model is updated.
You saw that the event not fired unless you click the window or something but do note that it could fire several times too

Silverlight Binding to commands

Sometimes when I bind to commands to a ViewModel, my CanExecute code does not always get called and hence my buttons are not disabled when they should be.
Any ideas?
Thanks
When canExecute is not called the first time, that's a binding problem.
If it's not 'automatically' called second,[n]th time, that's the normal behavior.
Imagine, how the UI should know that it should requery your predicate? When you have a command parameter it will call your predicate every time the parameter changes. Generally, some UI 'events' also requery it (focus, updatelayout etc), but not always (that's good, it would be pointless to reevaluate every command binding all time). So you cannot rely on it. You make the business logic, so you know when it needs an update, not the UI. The UI 'cannot see inside your predicate delegate' and watch what happens. You have to notify the UI about it, same as you notify when a property changed.
ICommand has an event, so you must implement it, it's the CanExecuteChanged.
You should implement a public method to fire it (or it is already implemented if you use a framework, like MVVMLight or Prism).
A simple implementation.
public void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
So you can call it on your command whenever your canExecute state changes in your business logic and it is going to notify all the subscribers, which is your button in this case.
You mention the state of the button not being disabled. This seems more like a binding issue than binding to commands. Is the state of the property you are binding to changing? When is it changing, etc.?

Are there any performance implications with CanExecuteCommand?

What are the performance implications of using the CanExecuteCommand of the ICommand object. Is the method executed over and over again?
I need to iterate through a collection of about 200 objects based on which its decided whether the button bound to the Command should be enabled? Does the CanExecuteCommand get executed repeatedly which will make my application slow
The ICommand interface is the following:
public interface ICommand
{
// two methods
bool CanExecute(object parameter);
void Execute(object parameter);
// one event
event EventHandler CanExecuteChanged;
}
The CanExecuteChanged event should be raised any time you want to indicate that the CanExecute method should be checked/called by WPF. Whoever implements ICommand should raise the event and whoever needs to refresh the button enabled state on the GUI (the WPF system) should register for and handle the event and it calls CanExecute.
In Josh Smith's RelayCommand class, he uses WPF's built-in CommandManager class to raise CanExecuteChanged:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
In essence, WPF's CommandManager is a singleton that listening for all sorts of routed events: KeyUpEvent, MouseUpEvent, etc... and then tells everyone "hey something interesting happened" by raising its RequerySuggested event. So if you are using RelayCommand, your CanExecute will get called every time CommandManager thinks something interesting happened on the GUI (even if it has nothing to do with your collection). If you have 50 commands, each time you key up, it's rechecking all 50 commands. So yes, this could be a performance issue. However, if your logic in your CanExecute method is really simple, it's probably a non issue. Takeaway point: don't make database or network API calls in the CanExecute method.
The alternative to piggybacking off CommandManager.RequerySuggested to raise the ICommand.CanExecuteChanged event is to roll-your-own version of RelayCommand where you do your own checking and raise CanExecuteChanged manually, or look at the Prism framework's DelegateCommand class, where they do not tie into CommandManager and you have to manually raise the CanExecuteChanged event, which you could probably do by creating a listener for PropertyChanged and then raising CanExecuteChanged on the command.
I agree with #Will above though. RelayCommand will probably work over 80% of the time without issues. If you do start finding performance issues, then you can create your own version of RelayCommand or use the Prism DelegateCommand and raise CanExecuteChanged manually.
For future googlers:
I have created a somewhat different command implementation. For one, it is bound to the OnPropertyChanged event of the ViewModelBase class, but it also allows the View Model to Raise the CanExecuteChanged event for all Command instances within it, regardless of a change in property, such as in the case of a One Way To Source binding scenario.
this solution is a part of the PerrypheralFrameowrk.WPF Assembly, available on nuget and codeplex. Look it up. The codeplex wiki has a detailed documentation, and so do the classes in the assembly.

How or when to cleanup RelayCommand objects in WPF/MVVM?

I am using the standard Josh Smith implementation of RelayCommand to implement ICommands in my WPF/MVVM application. See: WPF Apps with the MVVM Design Pattern
A few of my CanExecute methods take a long time to run. Individually, they aren't bad (a fraction of a second each). But I have noticed that the more commands that I bind to my UI, the slower the application responds (delays exceeding 10 seconds - yuck).
I believe it is because the RelayCommand CanExecuteChanged is hooking onto the CommandManager.RequerySuggested event and my ViewModel template calls CommandManager.InvalidateRequerySuggested() as part of the IDataErrorInfo validation.
My ViewModels implement IDisposable, so I have tried to take advantage of the OnDispose method to clean up my RelayCommands, but the ICommand.CanExecute methods continue to be called even after my VM is disposed of.
That leads me to conclude that something (the CommandManager?, the View?) is holding a reference to the RelayCommand.
Does anyone have a good pattern for releasing and disposing of RelayCommands to prevent them from being requeried after their desired lifetime has expired?
Is there a better way to manage when CanExecute should be called?
You can take out the CommandManager.RequerySuggested and use MVVM Light's RelayCommand implementation. Note: this requires you to explicitly call RaiseCanExecuteChanged() anytime you want CanExecute to be updated.

Are "volatile" data bindings in Windows Forms possible?

Let's assume I'm implementing a Winforms UI where all commands adhere to the following pattern:
interface ICommand
{
bool CanExecute { get; }
void Execute();
}
Buttons or menu items that trigger such a command should have the following set-up:
property Enabled is bound to the command's CanExecute
event Click is linked to the command's Execute (through an intermediate event handler due to the differing method signatures)
The trouble with CanExecute is, implementing INotifyPropertyChanged for it won't work here, as this property cannot be directly modified, but depends on other factors in the program which needn't be related to the command. And one shouldn't have to trigger the command's PropertyChanged event in completely unrelated parts of the program.
How do you let the data binding manager know when CanExecute has changed?
Here's a (purly fictional) example of my problem:
bool CanExecute
{
get
{
return User.LoggedInForAtLeastNMinutes(5);
// how would you trigger data-binding updates for CanExecute?
}
}
Ideally, I'd like to have the UI constantly checking CanExecute (as if it were a volatile field), but AFAIK this is not how Winforms data binding works. Does anyone have a solution for this problem?
Note: I am aware of WPF, btw. The background of my question is that I'm going to gradually improve an existing Winforms application in the general direction of WPF. But actually using WPF and thus getting rid of the problem I've asked about is not feasible right now.
I would implement INotifyPropertyChanged regardless (or add a CanExecuteChanged event, which has the same effect). I would try hard for objects to know when to raise the property changed event at the right time, rather than polling.
For instance, in your fictional example, you could have a UserLoggedIn event. In response to that, you could set a 5-minute timer; when that timer elapses, you raise the property changed event.
If you go for the polling approach then you face two dangers:
Polling too often, where your application consumes CPU checking for events that can't possibly happen yet (for instance, polling every 10 seconds to see if 5 minutes are up)
Not polling often enough, where controls bound to CanExecute properties lag the rest of the UI (for instance, a delay between making a text selection and the CopyTextCommand.CanExecute property updating)
A hybrid approach is that taken by Microsoft Foundation Classes in C++, which was to make this check any time the application's message loop was idle. This is a reasonable approach when you know that only user interface interaction that can affect your CanExecute property.
Use a Timer to constantly poll the CanExecute property. Raise the PropertyChanged event when the property changes.
I' do the polling on the Application.Idle event, as long as your can execute logic is simple, there shouldn't be any problem.
here is an extract of my current 'CommandManager' implementation;
public CommandManager()
{
Commands = new List<ICommand>();
Binders = new List<ICommandBinder>
{
new ControlBinder(),
new MenuItemCommandBinder()
};
Application.Idle += UpdateCommandState;
}
private void UpdateCommandState(object sender, EventArgs e)
{
Commands.Do(c => c.Enabled);
}
(Do() is just an extension method that does a foreach, like linq Select() but taking Action instead of Func)
I've blogged about this some time ago, feel free to check: http://codewithpassion.blogspot.com/2010/11/icommand-and-commandmanager-for-windows.html
hope it helps

Resources