2009年2月23日月曜日

[.NET]Formアプリケーション画面更新(マルチスレッド)

.NET Framework1.1までは特に意識することなく実行できていましたが、.NET Framework2.0以降でWindowsFromアプリケーションをマルチスレッド処理する場合、ちょっとした注意が必要です。
対処方法は2つありあます。コードは以下のとおり。

■Invokeを使う(正統派)
/// <summary>
/// Invokeを使ったマルチスレッド処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnInvoke_Click(object senderEventArgs e)
{

    //Threadを生成する
    Thread thread = new Thread(delegate() {
        //50回ループする
        for (int i = 0i < 50i++)
        {
            Thread.Sleep(500);
            //描画処理をinvokeする
            textBox.Invoke(new MethodInvoker(delegate() { 
                textBox.Text = i.ToString();
                textBox.Update();
            }));
        }
    });

    thread.Start();
}


しかし、旧来のシステムを移行する場合これらの対応を入れていくのは非常にメンドクサイ。別途動作確認をし、問題点のみInvokeを使って解決することを前提とすれば、フラグの制御のみでマルチスレッド化が実現できる。

■Control.CheckForIllegalCrossThreadCallsを使う(下位互換)
/// <summary>
/// CheckForIllegalCrossThreadCallsを使ったマルチスレッド処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnNoInvoke_Click(object senderEventArgs e)
{
    //Control.CheckForIllegalCrossThreadCallsをtrueにすればInvokeとほぼ同等になる
    //Control.CheckForIllegalCrossThreadCalls = true;

    //Threadを生成する
    Thread thread = new Thread(delegate()
    {
        //50回ループする
        for (int i = 0i < 50i++)
        {
            //500ms待機してテキストを更新する
            Thread.Sleep(500);
            textBox.Text = i.ToString();
            textBox.Update();
        }

    });

    thread.Start();
}


私自身は実験していませんが、デバッグモードでは実行時にエラーとなるが、リリースモードでは実行時にエラーにならないらしいです。移行の過渡期なんだろうか。。。

0 件のコメント: