今回紹介する方法で実装する場合、検索中はあらゆるイベントを処理できなくなりますので、フォームサイズ変更、コントロールの使用不可にするなどの処理も行えなくなります。メッセージループなど、Windowsプログラムの仕組みを理解していることを前提として説明しています。
検証環境は次のとおり
- OS:Windows Vista Enterprise
- IDE:Visual Studio 2008 Professional
動作はVista, Visual Studio 2008のデバッグ実行で確認しています。
1.フォームを作成して、検索作業中かのプロパティを定義します。
private bool _eventEnabled = true; protected virtual bool EventEnable { get { return _eventEnabled; } set { _eventEnabled = value; } }
2.DefWndProcをオーバーライド
DefWndProcをオーバーライドしてEventEnableがtrueのときのみイベント処理を行うようにします。
protected override void DefWndProc(ref Message m) { if (EventEnable) { base.DefWndProc(ref m); } else { } }
3.イベント無効化処理コード
以上で準備は完了です。検索ボタンが押された場合に次のようにプログラムを記述します。
private void btnSrch_Click(object sender, EventArgs e) { Cursor = Cursors.WaitCursor; try { EventEnable = false; //Application.DoEvents(); // この間では画面イベント(メッセージ表示)も表示しない // エラーが発生してもenabled=true以降でメッセージを // 表示すること System.Threading.Thread.Sleep(5000); } finally { EventEnable = true; Cursor = Cursors.Default; MessageBox.Show("これ以降イベント処理可能"); } }
4.まとめ
以上で終わりですが、この処理をするとフォームが無反応になります。EventEnabledをfalseにしたらEventEnabledをtrueにするのを忘れないで下さい。個人的には重い処理をするときは、ダイアログを表示して、処理中ですとのメッセージをだすようにして、別スレッドで検索を行い、ユーザ入力をさせないようにしたほうが、ユーザフレンドリーだと思うのですが、今回ご紹介した方法で対応することもできるという一例です。(フラグで検索中かの判定をしようと私が参加していたあるプロジェクトで決まり、その方法ではあらゆるユーザイベントの処理をサブスクライブして、フラグを見る処理を加えるという処理をしなくてはならず、絶対にいやだったので、今回のような回避策を提案しました。)
長い処理をしたときの他の回避策として、ワーカスレッドで重い処理を実施する方法もあります。また、ボタンの2度押し防止のためにクリックイベント中にボタンおEnabledプロパティをfalseにしてApplication.DoEventメソッドを呼び出す方法も考えられます。button1のクリックを2度押させないようにするには次のように行います。
private void button1_Click(object sender, EventArgs e) { button1.Enabled = false; Application.DoEvents(); System.Threading.Thread.Sleep(4000); MessageBox.Show("処理完了"); button1.Enabled = true; }
さんのコメント: さんのコメント: