を含む単純な WPF プログラムがありICommandます。ボタンが期待どおりに有効/無効にならないことがわかりました。これは、不自然なコード例で最もよく説明できます。
class Reload : ICommand
{
private readonly BackgroundWorker _bworker = new BackgroundWorker();
public Reload()
{
this._isExecuting = false;
this._bworker.DoWork += this._bworker_DoWork;
this._bworker.RunWorkerCompleted += this._bworker_RunWorkerCompleted;
}
public event EventHandler CanExecuteChanged;
private void OnCanExecuteChanged()
{
if (this.CanExecuteChanged != null)
this.CanExecuteChanged(this, EventArgs.Empty);
}
private bool _isExecuting;
private void SetIsExecuting(bool isExecuting)
{
this._isExecuting = isExecuting;
this.OnCanExecuteChanged();
}
public bool CanExecute(object parameter)
{
return !this._isExecuting;
}
public void Execute(object parameter)
{
//this does not update the GUI immediately
this.SetIsExecuting(true);
//This line doesn't fix my problem
CommandManager.InvalidateRequerySuggested();
//during this wait, button appears "clicked"
Thread.Sleep(TimeSpan.FromSeconds(2)); //simulate first calculation
this._bworker.RunWorkerAsync();
}
private void _bworker_DoWork(object sender, DoWorkEventArgs e)
{
//during this wait, button appears disabled
Thread.Sleep(TimeSpan.FromSeconds(2)); //simulate second calculation
}
private void _bworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//this updates immediately
this.SetIsExecuting(false);
}
}
このメソッドでは、 false を返すようにイベントExecute(object)をトリガーします。その呼び出しの後、ボタンがすぐに無効になることを期待していますが、呼び出しと2番目のシミュレートされた計算の間のある時点まで無効になりません。CanExecuteChangedCanExecute(object)RunWorkerAsync()
バックグラウンド ワーカーのRunWorkerCompleted(...)イベント ハンドラーで、再びCanExecuteChangedイベントをトリガーしますが、今回はCanExecuteChanged(object)true を返すようにします。この呼び出しの後、ボタンはすぐに有効になります。
CanExecuteChangedイベント をトリガーしても、ボタンがすぐに無効として表示されないのはなぜですか?
注 #1: 最初のシミュレートされた計算は、メインの GUI スレッドで実行する必要があるコードを表しています。この呼び出しを削除すると、ボタンは期待どおりに機能します。
CommandManager.InvalidateRequerySuggested()注 #2:コードにメソッドを強制的に呼び出すためのusing について読みましたCanExecute(object)。コメントで、これがうまくいかないことを示しました。を呼び出すOnCanExecuteChanged(...)ことを考えると、その提案はとにかく冗長だと思います。