はじめに
C#で、特定のフォーム内のコントロールに対する作業をバックグラウンド(別スレッド)で行っている間、フォームへのアクセスを禁止するには、「this.Enabled = false」を指定するだけで事足ります。
しかし、テキストボックスなどの編集可能なコントロールは、使用不可能になるとグレイアウトするため、処理が一瞬で終わるような場合、ユーザーには画面がちらついたような印象を与えてしまいます。
そこで本稿では、EnabledやTextプロパティの変更をはじめとする、バックグラウンド作業中のコントロールの更新やアクセスをユーザーから隠す方法について紹介します。
対象読者
.NET Frameworkにおいてマルチスレッドによるコントロール処理を検討している方。
必要な環境
Visual C# 2005以降、あるいはそれに準ずる開発環境。サンプルプログラムはVisual Studio 2008で作成し、Windows Vistaで動作確認しています。
フォームの再描画を抑止する方法
バックグラウンド処理が1秒以内で終わるような簡単なものであれば、フォームの再描画を一時的にやめさせることで、コントロールのグレイアウト処理を無視することができます。
フォームの再描画を抑止するにはWin32APIのSendMessageでWM_SETREDRAWを対象のフォームに通知します。wParamの値が0であれば再描画の禁止、1であれば再描画の許可となります。下のコード例の場合、BackgroundWorkerが動作しているときは、パネル内のコントロールを使用不可にする前に再描画を禁止するため、見かけ上はコントロールに変化がないように見えます。
なお、再描画を許可した直後は、Refreshメソッドによってウィンドウを明示的に更新する必要があります。
[DllImport("user32")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, long wParam, long lParam);
private const uint WM_SETREDRAW = 0x000B;
private void button1_Click(object sender, EventArgs e)
{
// ウィンドウの再描画を無効にする
SendMessage(panel1.Handle, WM_SETREDRAW, 0, 0);
panel1.Enabled = false;
// バックグラウンド処理の開始
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
// 再描画を有効にして最新の状態に更新
panel1.Enabled = true;
SendMessage(panel1.Handle, WM_SETREDRAW, 1, 0);
panel1.Refresh();
}
