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.

5 Comments

  1. Lo says:

    Great !! Just what I needed !! Thanks a lot from the team 😉

  2. Adrian says:

    Very good post. Thanks a lot for the help. I really needed this information

  3. Dan Jarvis says:

    This was just what I needed… THANKS.

  4. […] Refreshing a button enabled/disabled by RelayCommand.CanExecute() […]

Leave a Reply

*