進行状況メーターコントロールを表示するWPFダイアログと、進行状況の更新を示すバックグラウンドタスク(System.Threading.Tasks.Task
)があります。プログレスメーター。 2人の間のメディエーターはSystem.Progress<T>
オブジェクトです。WinFormsダイアログが表示された後、メインスレッド上でイベントが発生しないSystem.Progress
このすべてが「通常」の状況下で完璧に動作します:
- バックグラウンドタスクは、メインスレッドではない、いくつかのスレッドX上
System.IProgress.Report()
を呼び出します。 System.Progress
オブジェクトは、System.Progress
オブジェクトは、メインスレッド上ProgressChanged
イベントが発生したスレッド- を切り替え、内部の魔法を行います。
- 進捗メータ制御が、私は任意ののWinFormsダイアログを開いた場合、その後、その後、それを閉じて私のバックグラウンドタスクを開始し、
今(コントロールを所有している)は、メインスレッド上で更新され、System.Progress
が突然発火しますProgressChanged
イベントはメインスレッドではなく、メインスレッドではないスレッドYにあります。イベントハンドラがコントロールを所有しているスレッドとは別のスレッドでWPF進行状況メータコントロールを更新しようとするため、これはもちろんInvalidOperationException
になります。
私はそれを言ってSystem.Progress
ためのドキュメントを気づい:
を、インスタンスの作成時に[...]
ProgressChanged
イベントに登録されたイベントハンドラがキャプチャSynchronizationContext
インスタンスによって呼び出されます。構築時に現在のSynchronizationContext
がない場合、ThreadPool
でコールバックが呼び出されます。
これはSystem.Progress
が悪い場合には、そのイベントを発生時にコールスタックの下の部分がどのように見えるかであるので、これは、私が観察できるものと一致しているようだ:
[...]
bei System.Progress`1.InvokeHandlers(Object state)
bei System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
bei System.Threading.ThreadPoolWorkQueue.Dispatch()
bei System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
私はの値をチェックしますSystem.Progress
オブジェクトが作成された時点ではSynchronizationContext.Current
プロパティですが、nullになることはありません。プロパティによって返さSynchronizationContext
オブジェクトには、次の種類があります。
- 良い場合(つまりリサイズダイアログを開く前に):オブジェクト:オブジェクトは
System.Windows.Forms.WindowsFormsSynchronizationContext
- 悪い場合(つまりリサイズダイアログを開いた後)であります
System.Threading.SynchronizationContext
は、残念ながら私はWinFormsのではない多くの経験、そして全くSynchronizationContext
とどれを持っているので、私はここで何が起こっているかの損失でかなり午前です。
なぜWinFormsダイアログを開くとSynchronizationContext.Current
の値が変わるのですか?これはなぜSystem.Progress
の動作に影響しますか? System.Progress
の自分自身の書き換えを書いていないのに、問題を「修正」する方法はありますか?
EDIT:実行ファイルがコアでMFCアプリケーションであり、.exeプロジェクトが/ CLRでコンパイルされ、見ているC#コードがC++/CLI経由で呼び出されることがあります。 C#コードは.NET Framework 4.5.1用にコンパイルされています(実行中)。複雑な設定は、アプリケーションが現代的な態度を持つ伝統的な獣であるためです:-)これまでのところ、これは私たちのために非常にうまくいっています。
メインUI以外のスレッドでダイアログフォームを表示していますか? –
@IvanStoevいいえ、私はメインのUIスレッドでWinFormsダイアログを表示しています。また、メインのUIスレッドでWPFの進行状況ダイアログを表示しています。 – herzbube
あなたが正しいように見えます。 'WindowsFormsSynchronizationContext'は、内部メッセージループ回数が0になると自動的にアンインストールされます。通常、WFアプリケーションでは発生しません。メインループ(' Application.Run')は常に1つあります。たとえあなたが何とかそれを騙しても、実際に正しく動作するためにはメッセージループをサポートする必要があります。 –