2009-04-29 9 views
0

私のWinFormsアプリケーションでは、X秒間画面にとどまる小さなカスタムダイアログをポップアップして消える必要があります。だから、適切な時間が経過したら、System.Threading.Timerを使用して_dialog.Close()メソッドを呼び出します。これは、もちろん、私が"InvokeRequired BeginInvoke"ダンスの全体をやらなければならないことを意味します。これは実際問題ではありません。winformが正確にX秒で終了するようにする方法

しかし、私のメインスレッドは、BeginInvokeが呼び出されるまでに何が起こっているのかを知っている可能性があります。それはかなり長い間、ウィンドウを閉じることを回避できないかもしれません。私はミリ秒の通知でウィンドウを閉じる必要はありませんが、1秒程度で本当に必要です。

私の質問は、BeginInvokeが実際にメインスレッドにどのように機能するのか、この奇妙な制限を回避するにはどうすればよいですか?

+0

なぜあなたは.visible = falseを使用して閉じないのですか? –

+1

UIスレッドがそのような遅延を引き起こしていることは何ですか? – BobbyShaftoe

+0

@Daniel、visibleプロパティの設定にはClose()の呼び出しと同じ問題があります。 – BobbyShaftoe

答えて

4

UPDATE:結論はSystem.Windows.Forms.Timerとともに['BackgroundWorker]http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx)を利用することは最善のアプローチになることであるように見えるでしょう。

この目的のためにSystem.Windows.Forms.Timerを使用することをお勧めします。これはまさにそのために設計されたアプリケーションの種類です。ポップアップフォームに1を追加し、フォームが表示されるとすぐに開始し、Tickイベントでフォームを非表示にします。このソリューションでは、スレッドがUIスレッドのみで実行されるため、スレッドの問題は発生しません。

編集:あなたがポップアップ形式の外にロジックを移動したい場合は、私はあなただけでそのパラメータのタイムスパンを取り、設定の仕事をして、フォームのコード内Showメソッドのオーバーロードを作成するお勧めしますTimersの間隔を指定して開始してください。

編集2:メイン(UI)スレッドがあまりにも多くの作業をしているため、メッセージポンプをブロックしてタイマーを起動できない場合は、私が恐れる問題です。あなたのUIスレッドは、となることはありません。は数分の1秒以上ブロッキングしてください。深刻な作業をする必要がある場合は、ワーカースレッドを使用してバックグラウンドで実行します。この場合、WinFormsを使用しているため、おそらくBackgroundWorkerが最適なオプションです。

+0

しかし、フォーム自体は、いつ閉じるのかを知っている必要があります!それは解決策ではない、私はwinformの外でできるだけ多くのロジックを維持しようとしている。 –

+0

これは、そうでなければ占有されているUIスレッドの問題を解決しません。 –

+0

@ George:投稿が更新されました。 – Noldorin

1

Invokeは、呼び出すスレッドのメッセージキューにデリゲートを配置するだけです。 Dispatcherクラスを使用して優先度の高いデリゲートを挿入することはできますが、スレッドが多くの作業を行っている場合にはタイミング制約を満たすことはできません。

しかし、これはユーザーインターフェイススレッドで多くの作業を行っていることを示している可能性があります。 1秒間応答しないとユーザーには苦痛があります。だからあなたは、ユーザーインターフェイスのスレッドからいくつかの作業を動かすことについて考えるかもしれません。

+0

絶対に、私はこれをやろうとしていますが、実際にこれを行うのは簡単ではありません。これに関するベストプラクティスに関するチュートリアルや記事はありますか? –

+0

チュートリアルは何ですか? GUIからの作業やDispatcherクラスの使用を考慮しますか? –

+0

アプリケーションの実際の作業をUIスレッドで実行する方法については、私はMVPアーキテクチャーを使用していて、BackgroundWorkerで各プレゼンター呼び出しをラップするのは短すぎます(これは厄介ですが、可能性があります)これを行う方法は他にありません。 –

3

専用スレッドを作成し、Application.Runを使用してフォームを作成して表示します。これにより、メインスレッドとは独立した2番目のスレッドでメッセージポンプが起動します。何らかの理由でメインスレッドがブロックされていても、必要なときにこれを正確に閉じることができます。

InvokeとBeginInvokeは、そのスレッドにポストされたウィンドウメッセージを使用してメインスレッドに入り、処理を待っています。したがって、メインスレッドのメッセージポンプがメッセージ(例えばビジー)を処理していない場合、それは待機しなければならない。メインスレッドで時間のかかる操作を実行するときにApplication.DoEvents()を呼び出すことでこの要素を軽減できますが、それは実際問題の解決ではありません。

編集:いくつかのスプラッシュ画面コードからサンプル(フォームは特別なコードやロジックを必要としません):

​​
+0

+1。ちょうど私が投稿しようとしていたもの! –

+0

もう説明できますか?興味をそそられる。 –

+0

詳細な説明は何ですか?スプラッシュ画面や未処理の例外ダイアログを表示するために、この「すべての時間」を使用します。これにより、メインスレッドがロックされ、それと同時に専用ダイアログの応答UIが独自のスレッド上で提供されます。 – Lucero

5

あなたのUIスレッドはその後、一度に多くの秒のビジー状態の場合:

  • Application.DoEvents呼び出しでコードをペーストせずに、そのUIスレッドに関連付けられたウィンドウを閉じることはできません
  • UI全体が応答しなくなりますduri今回は。ユーザーはアプリケーションのウィンドウを移動することはできません。ユーザーが他のウィンドウをドラッグして再び上に移動すると、UIが再描画を待つ間に醜い混乱に終わります。

確か代わりに、単純化のためSystem.Threading.TimerSystem.Windows.Forms.Timerを使用していますが、より早急に、そのような忙しいUIスレッドを避けるために、あなたのコードを修正見てください。

+0

ええ、私が上記のコメントで言ったように、ビジネスがテストに使用されたメッセージボックスからのものであり、それらを削除しても何の問題もない可能性があります。私の意見では、SoCのかなり悪い休憩であるForms Timerの使用については、私のダイアログでは、いつ、誰がそれを閉じようとしているのか、外部からの呼び出しであるのかを知るべきではありません。 –

+0

ダイアログは知る必要はありません。Closeを呼び出す前に、スレッドが正しいスレッドにあることを確認するために、呼び出し側が指定する必要があります。私には全く合理的に聞こえる。必要に応じて、System.Timers.Timerを使用してTimer.SynchronizingObjectを設定することもできます。あなたは他のすべてのGUI要素と同じ要求をしています。 –

関連する問題