WPF の Dispatcher について勉強してみた(XPでの描画遅延回避編)

XP での描画遅延の問題(Button の Enable/Disableが切り替わらない)を回避するのに、自前の RelayCommand を以下のように実装してみました。

/// <summary>
/// 現在の状態でこの RelayCommand を実行できるかどうかを判断します。
/// </summary>
public bool CanExecute(object parameter) {
    var ret = _canExecuteAction();
    System.Windows.Application.Current.Dispatcher.Invoke(
        new Action(() => {}), 
        DispatcherPriority.Background
    );
    return ret;
}

ちなみにこの話はフォーラムやTLで少し話してます。TL はこの辺り、フォーラムは以下のスレッドです。
WPF TextBox.AppendTextにより文字列が追加されるタイミングについて


これで Button の描画遅延を回避できたのですが、ContextMenu にバインドさせたコマンドで、なぜか CanExecute メソッドがコールされません。DispatcherPriority を Normal にすると CanExecute は実行します。

public bool CanExecute(object parameter) {
    var ret = _canExecuteAction();
    System.Windows.Application.Current.Dispatcher.Invoke(
        new Action(() => {}), 
        DispatcherPriority.Normal
    );
    return ret;
}


そこで、Dispatcher.BeginInvoke を使って xxxxCommand.RaiseCanExecuteChanged を実行するよう変更してみました。

public void CanExecute() {
    System.Windows.Application.Current.Dispatcher.BeginInvoke(
        new Action(() => {
           xxxxCommand.RaiseCanExecuteChanged();
        }), 
        DispatcherPriority.Background // シーンにより優先度を使い分ける必要あり
    );
    return ret;
}


これでメニューにバインドしたコマンドの CanExecute も実行されるようになり、XP の描画遅延も回避されました。しかしこの辺りの挙動がまだ理解できてません。もっと調査しなければ・・・当面は Windows のスレッドから勉強し直しです(汗)
スレッドに関しては、プログラミング .NET Framework 第三版の第5部に 170頁以上使いかなり突っ込んで解説してあったので今読んでますが、Windows のスレッドの仕組みと設計思想が詳しく説明されてるのでなかなか面白いです。これはいいかも!

プログラミング.NET FRAMEWORK 第3版 (Microsoft Press)

プログラミング.NET FRAMEWORK 第3版 (Microsoft Press)