はじめに
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(); }