2013年4月11日木曜日

wpf : ウェイト処理でTaskとDispatcherを組み合わせないとダメだった

wpfでStoryboardを使ってアニメーションするコードを書いたときのお話。 アニメーションが始まってからちょっとまって次の処理を走らせるため、こんなコードを書きました。

Dispatcher.BeginInvoke((Action)(() =>
{
    Thread.Sleep(TimeSpan.FromMilliseconds(1000));
    処理
}));

このコードは正常に動きませんでした。 1つのコントロールで試したときは大丈夫だったんですが、2つのコントロールで試すと片方のアニメーションが想定どおりに動きませんでした。

Dispatcher.BeginInvokeはGUIのスレッド上で処理を走らせるためのメソッドです。 GUIのスレッドから上のコードを呼び出すと、スレッドの実行順や優先順位の関係で上手く動かないようです。

肝心のスレッドの実行順や優先順位がどうなっているのかはよく分かりませんが、とにかくGUIスレッドではない別のスレッドでウェイトをかけないとダメなようです。

Task.Factory.StartNew(() =>
{
    Thread.Sleep(TimeSpan.FromMilliseconds(1000));
    Dispatcher.BeginInvoke((Action)(() =>
    {
        処理
    }));
});