Refreshing a button enabled/disabled by RelayCommand.CanExecute
When using the RelayCommand class, a command class used for MVVM development, you may find times when a button that is enabled or disabled based on RelayCommand.CanExecute does not refresh until a keyboard or mouse click. When this happens you may have to manually force this refresh to occur. You can force the refresh in the ViewModel with this function:
CommandManager.InvalidateRequerySuggested();
If you want to see this in action, you can download the LDPing project I have recently made.
svn co https://ldmsplugins.svn.sourceforge.net/svnroot/ldmsplugins/LDPing
You don’t need to know about LANDesk or know what an LDPing is to understand what is going on enough to see how to use this one function. In the LDPing project, clicking the button starts a background process to run an LDPing. The button disables when clicked. Once the ping is finishes, the button should enable, however, originally it didn’t enable. I had to add the CommandManager.InvalidateRequerySuggested() function.
Here is the code:
/// <summary> /// This is the Ping method that launches an LDPing as a BackgroundWorker process, using /// PingWorker which is an object that inherits BackgroundWorker and adds one property called /// PingSucceeded. /// </summary> private void Ping() { IsPinging = true; ClearPingResults(); PingWorker worker = new PingWorker(); worker.DoWork += new DoWorkEventHandler(worker_DoPing); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_PingCompleted); worker.RunWorkerAsync(); } void worker_DoPing(object sender, DoWorkEventArgs e) { Stopwatch timer = new Stopwatch(); timer.Start(); // Now lets ping PingWorker worker = sender as PingWorker; LDPing tmpLDPing = LDPingAction.AgentPing(IPAddress); if (tmpLDPing == null) worker.PingSucceeded = false; else worker.PingSucceeded = true; timer.Stop(); // Lets make sure the GUI spinner has at least a little spin int i = 1200 - (int)timer.ElapsedMilliseconds; if (i > 0) Thread.Sleep(i); LDPing = tmpLDPing; } void worker_PingCompleted(object sender, RunWorkerCompletedEventArgs e) { IsPinging = false; PingWorker worker = sender as PingWorker; if (worker.PingSucceeded) ConnectionResult = "Ping Successful."; else ConnectionResult = "Ping failed."; // This makes the UI refresh against the RelayCommand.CanExecute() function. // Essentially, this makes the button enable when pinging is done. CommandManager.InvalidateRequerySuggested(); }
Without the CommandManager.InvalidateRequerySuggested() function, the button’s enabled state doesn’t refresh until an event such as a keyboard or mouse click.