WPFキャンバス:Children.Add()がバックグラウンドスレッドでハングしていますか?
-
03-07-2019 - |
質問
...または...
" WPFの奥深くで目覚めた悪とは?"
バックグラウンドスレッドでCanvasを作成し、ビットマップにレンダリングしています。私はこれを問題なく1年以上本番コードで動作させてきました。私は次のことをします:
- Canvasオブジェクトを作成
- 新しいNameScopeオブジェクトを作成
- そのNameScopeをキャンバスに割り当てます
- キャンバスに好きなものを描く
- キャンバスのサイズでcanvas.Measure()を呼び出します
- Canvasの使用可能な四角形でcanvas.Arrage()を呼び出します
- canvas.UpdateLayout()を呼び出す
- キャンバスをレンダリング
描画ステップでは、常にcanvas.Children.Add()を呼び出して、UIElementsをCanvasに配置しました。これは常に機能しています。
現在、何らかの不可解な理由で、作業中のアプリケーションの特定のケースでは、canvas.Children.Add()の呼び出しが無限にハングし、バックグラウンドスレッドをブロックしています。 1年以上にわたって機能しているコードと、この1つの特定のケースとの間で、私が違うことをしていることは考えられません。
canvas.Children.Add()の呼び出しがこのようにハングする可能性のある理由を誰でも提案できますか?
編集:バックグラウンドスレッドはSTAスレッドです(MTAスレッドでWPFを使用して画像を処理できなかったため、バックグラウンドスレッド処理モデルが配置されました)。したがって、スレッドアパートメントモデルは犯人ではない。
編集#2 :バックグラウンドスレッドからDispatcher.BeginInvoke()を試してみることを人々が提案している理由は理解していますが、次の2つの理由でそのオプションが好きではありません。
- バックグラウンドスレッド処理をそのスレッドで同期させたい。私のバックグラウンドスレッドには他のスレッドが画像ジョブを送信するキューがあり、バックグラウンドスレッドは各ジョブが到達するたびに処理します。 Dispatcher.BeginInvoke()を使用すると、別の複雑さのレイヤーが追加されますが、これは避けたいものです。
- 今まで 必要 はありませんでした。バックグラウンドスレッドでこのバックグラウンド処理を同期的に実行することは、単純に作業するだけです。このコードが機能しない原因となるこの奇妙なエッジケースについて、何が異なる可能性があるかを判断しようとしています。動作しない場合は、WPFを使用せずにこの処理コードを書き直すことになりますが、これも避けたいと思います。
解決
バックグラウンドスレッドに使用しているアパートメントモデルは何ですか?
WPFはSTAスレッドで実行する必要があると思います。バックグラウンドスレッドを生成するとき、STAへのアパートメントの設定を試してください。
更新:
STAスレッドに問題がない場合は、キャンバスの描画を分割してみます。基本的に次のことを行う場合:
Dispatcher.BeginInvoke(...)
スレッドから、提供されたデリゲートはディスパッチャキューの後ろにプッシュされ、他のキュータスクを実行できます。
更新2:
.NETフレームワークの参照ソースを使用して、Canvasオブジェクトのソースコードをデバッグすることもできます。これを有効にするには、「。net framework source steppingを有効にする」をオンにします。 [ツール]-> [オプション]のデバッグオプションで。
他のヒント
バックグラウンドスレッドでDispatcher.Run()を呼び出してみてください。