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.
Related
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.
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.
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
Let's have a button Command property bound to a custom command.
When should I implement ICommand and when derive from RoutedCommand? I see that RoutedCommand implements ICommand.
In which case could I need to implement an ICommand?
What about MVVM model? Which one suits better for this purpose?
As you have noticed the RoutedCommand class is an implementation of the ICommand interface, its main distinction if that its function is similar to that of a RoutedEvent:
The Execute and CanExecute methods on a RoutedCommand do not contain the application logic for the command as is the case with a typical ICommand, but rather, these methods raise events that traverse the element tree looking for an object with a CommandBinding. The event handlers attached to the CommandBinding contain the command logic.
The Execute method raises the PreviewExecuted and Executed events. The CanExecute method raises the PreviewCanExecute and CanExecute events.
In a case when you don't want the behavior of the RoutedCommand you'll be looking at your own implementation of ICommand. As for the MVVM pattern I can't say that one solution, it seems that everyone has their own methodology. However, here are a few approaches to this problem that I've come across:
Using RoutedCommands with a ViewModel in WPF
Relaying Command Logic
Simple Command (almost identical to Relay Command but worth reading)
The only thing I would add to Rich McGuire's answer is that RoutedCommands (and their more prevalent descendant RoutedUICommand have to be wired up with event handlers to work correctly.
Most MVVM implementations I have come across attempt to leverage binding against the ViewModel and thus the ViewModel (and not the View) owns the CanExecute/Execute logic.
In contrast, the event handlers move that burden to the View. The handling can then be propagated to the ViewModel, but this means a slightly higher degree of coupling between ViewModel and View (casting + method call, etc.).
I have been working on a WPF application and I am using the ModelViewViewModel design pattern. I have a number of events that come out of the view, that result in ViewModel activity.
What is the resonable way to get these events raised from a UnitTest? For example, I want to simulate the drop event. I don't really want to build a stub view, just to raise the event.
Any suggestions welcome.
Thanks.
According to the MVVM pattern:
The View knows about the ViewModel - it will have a reference to it either as a concrete instance or an interface
The ViewModel should not know about the view at all.
If you need to handle events, then there are two ways which I know of to do it:
1: Expose a command in your viewmodel, and use databinding to trigger it. This is my preferred way, eg:
class MyViewModel
{
public ICommand ClickCommand { get; set; }
}
<Button Command="{Binding Path=ClickCommand}" />
If you do this then you can test the command by simply calling myViewModel.ClickCommand.Execute manually.
2: Expose a function in the viewmodel, and write the absolute minimum in the .xaml.cs file to handle the event and call the function, eg:
class MyViewModel
{
public void HandleClick(){ }
}
<Button Click="MyClickHandler">
//.xaml.cs file
public void MyClickHandler( Object sender, EventArgs e ) {
m_viewModel.HandleClick()
}
If you do this, then you can test by simply calling myViewModel.HandleClick manually. You shouldn't need to bother with unit testing the MyClickHandler code as it's only 1 line!
It sounds like you have an event handler for the drop event directly in your ViewModel class. Would it make more sense to have the handler in your UI layer, which in turn will call a function in your ViewModel? This way, your unit test could just call the function (simulating a drag and drop operation, as far as the ViewModel is concerned).
Plus, it would better separate your ViewModel from your UI code.
Don't raise an event, just call the handlers (which means they should be public, and probably take less event handler centric arguments). Check out how this is done in Caliburn (http://www.codeplex.com/caliburn) using "Actions".
Why don't you use a mocking framework, such as Moq? Check out their quick start, it has a sample on mocking events. The url is: http://code.google.com/p/moq/wiki/QuickStart