You'd think that it would be as simple as using a Command and making CanExecute() return false while the command is running. You would be wrong. Even if you raise CanExecuteChanged explicitly:
public class TestCommand : ICommand
{
public void Execute(object parameter)
{
_CanExecute = false;
OnCanExecuteChanged();
Thread.Sleep(1000);
Console.WriteLine("Executed TestCommand.");
_CanExecute = true;
OnCanExecuteChanged();
}
private bool _CanExecute = true;
public bool CanExecute(object parameter)
{
return _CanExecute;
}
private void OnCanExecuteChanged()
{
EventHandler h = CanExecuteChanged;
if (h != null)
{
h(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
}
I suspect that if this command had a reference to the window's Dispatcher, and used Invoke when it called OnCanExecuteChanged, it would work.
I can think of a couple of ways to solve this problem. One's JMarsch's approach: simply track when Execute is called, and bail out without doing anything if it was called in the last few hundred milliseconds.
A more robust way might be to have the Execute method start a BackgroundWorker to do the actual processing, have CanExecute return (!BackgroundWorker.IsBusy), and raise CanExecuteChanged in when the task is complete. The button should requery CanExecute() as soon as Execute() returns, which it'll do instantly.