- - PR -
ShowDialogのようなメソッドの実装方法
1
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-10-03 00:53
お世話になっております。
件名のことで現在悩み中です。 一般的なFormの表示はこのようになると思います。
Formを継承したクラスではない、通常のクラスで同じようなことは実現可能でしょうか? つまり、ボタンのClickイベントハンドラで
というコードを実行した場合、 ・WaitメソッドはUIスレッド以外のスレッドで実行される。 ・Waitメソッド実行中もUIは応答する。 ・Waitメソッド終了後、ボタンのClickイベントハンドラに制御が移る。 ということは実現できるのでしょうか? ぱっと思いついた以下のコードでは、UIの応答性はよくありませんでした。
| ||||||||||||
|
投稿日時: 2006-10-03 09:18
結局ShowDialogはさておき一般的なマルチレッドだと思いますので
Threadクラス、BackGroundWokerクラス(コンポーネント)についてお調べになるとよろしいかと。 「参考」 http://www.microsoft.com/japan/msdn/vs05/vbasic/threadinginvb2005.aspx #あら、VB向けみたいなドキュメント
非同期で依頼をするので、後はその処理から通知を待つことになります。 | ||||||||||||
|
投稿日時: 2006-10-03 09:24
なんてコードを書いてしまったら、UIがブロックするのは避けられません。 Windows の GUI は、メインスレッドでメッセージポンプが回ることで応答性を確保しているのですから、イベントハンドラにブロックするコードを書けば、UI がブロックするのは当然です。 UI の応答性を確保したいなら、「時間のかかる処理」は別スレッドで実行し、メインスレッドはその終了通知を待ち受けるような構造にしなくてはなりません。 GUI ベースのアプリケーションを書いているなら、BackgroundWorker クラスを使うのが妥当な線だと思います。
VB6 で良く使われれていた手法ですね。 見た目に単純な解放ですが、実際には状態管理が異常に複雑化する場合があり得るので、個人的には避けるが吉と思います。 [ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2006-10-03 09:29 ] | ||||||||||||
|
投稿日時: 2006-10-03 12:53
みなさん、指摘されていますが、時間のかかる処理をそのまま別のスレッドで動かせばいいと思います。
イベント内には、 Thread newThread = new Thread(new ThreadStart(this.DoWork)); newThread.Start(); ってな感じで、書いてあげて、DoWork を void DoWork() { MyClass c = new MyClass(); c.HeavyWork(); // その後の、処理 } ってな感じで書いてあげればいいと思います。 実際の処理は、別のスレッドで動かしてやることで、イベントの処理をさっさと終わらせて、 別のスレッドの中で、その重い処理と、その後始末の処理をやってあげればいいはずです。 ただ、こんな感じでやると、そのボタンを連打した時に大変な事になる場合がある点に 注意が必要かと思います。 # VB 使いなんで、C# の文法が間違っていたら、すまんです。 | ||||||||||||
|
投稿日時: 2006-10-04 00:02
まどかさん、渋木宏明(ひどり)さん、わちゃさん回答ありがとうございます。
せっかく回答していただいたのに恐縮ですが、説明が足りなかったようです。 皆さん指摘されたように、時間がかかる処理を別スレッドにする、というのは理解しております。 実際には、MyClass#WaitメソッドはBackgroundWorkerを使用して時間のかかる処理を行っています。 このMyClassは解放が必要なリソースを使用していて、BackgroundWorker#RunWorkerCompletedイベントハンドラでMyClass#Disposeを呼んでいます。 ここまで実装して、ボタンのClickイベントハンドラで生成したのだから、そこでMyClassの破棄もやった方がわかりやすいのでは?と思いました。 1.起動トリガはボタンのClickイベントハンドラなどUIスレッドの処理 2.時間のかかる処理は別スレッドで行う。 3.別スレッドの処理が終了するとそのスレッドを起動した場所に制御が戻る。 4.その間にUIスレッドはブロックしない。 これらの条件を満たす方法があるのか?というのが質問です。 そこで似たようなコードになるShowDialogを引き合いに出して質問したわけです。 (2.が別フォームを表示するに対応するかと思います。) できないならできないで、今のまま実装します。 ちなみに、Application.DoEventsは苦肉の策です。普段使用することはありません。 | ||||||||||||
|
投稿日時: 2006-10-04 00:32
それでいいのでは?
非同期呼び出しですので以降のステップがすぐに実行し続けますよね。 なのでそこに書きたくても書けないと思うのですが。 [/quote] そこで似たようなコードになるShowDialogを引き合いに出して質問したわけです。 (2.が別フォームを表示するに対応するかと思います。) [/quote] これは単に同期呼び出しで別スレッドではないのでは? | ||||||||||||
|
投稿日時: 2006-10-04 22:34
まどかさん、回答ありがとうございます。
自分もそう思うのですが、もしかしたら方法があるのでは、と思って質問しました。
同期呼び出しなんでしょうか? ShowDialogが同期呼び出しなのであれば、UIスレッドはブロックされているはず。 しかし、別スレッドからUIスレッドに処理を委譲すると(Control#Invoke)きちんと処理されます。 そこがいまいち納得できてないわけなんです。 とりあえず最初の質問のようなことは無理そうなので、今の方法で実装します。 ありがとうございました。 |
1