私のアプリケーションでは、基本的に大きなディスプレイ (カスタム ユーザー コントロール) で構成される新しい Windows フォーム (Monitor と呼ばれます) があり、それ自体はグリッドに配置された多くの小さなグラフ (ユーザー コントロールも含む) で構成されています。モニター フォームをインスタンス化すると、新しい表示オブジェクトが作成され、続いて多数のチャート コントロールが作成されます。次に、チャート コントロールが「ディスプレイ」のコントロール コレクションに追加され ( Controls.Add(chart)
)、ディスプレイの読み込みが完了します。次に、ディスプレイが「モニター」のコントロール コレクションに追加され、フォームが表示されます。
私が抱えている問題は、各チャート コントロールの読み込みに約 0.5 秒かかり、1 つの表示オブジェクトに約 75 個のチャート コントロールを含めることができることです。したがって、ロード時間を短縮するために、これらのチャートを並行して作成したいと思います。これを実現するために TPL メソッドを利用Parallel.ForEach
しました。
私のコードは、「表示」オブジェクトのコンストラクター内で次のようになります。
public class DisplayControl : UserControl
{
public DisplayControl()
{
var chartNames = new string[] { "chart1", "chart2", ... };
var builtCharts = new ConcurrentBag<Chart>();
// Create the chart objects in parallel
Parallel.ForEach(chartNames, name =>
{
// The chart constructor creates the chart itself, which is a
// custom user control object (inherits UserControl), composed
// of other various WinForm controls like labels, buttons, etc.
var chart = new Chart();
chart.Name = name;
builtCharts.Add(chart);
}
);
// Clean up the charts and add them to "display's" control collection
foreach(var chart in builtCharts)
{
// Do some unimportant modifications to the chart, synchronously
...
this.Controls.Add(chart);
}
}
}
DisplayControl コンストラクターは、メイン フォーム Monitor によってメイン スレッドで呼び出され、DisplayControl インスタンス自体が Monitor の ControlCollection に追加されます。Monitor は、クラスのメソッドでMonitor.Show()
あるを使用して表示されます。Show
Form
私が経験している主な問題は、次のように、DisplayControl コンストラクターが行でInvalidOperationException
時折スローすることです。this.Controls.Add
System.InvalidOperationException: Cross-thread operation not valid: Control 'panel' accessed from a thread other than the thread it was created on.
これは、コンストラクターpanel
で作成された単なるパネル WinForms コントロールであることに注意してください。Chart()
最後に、コードは約 90% の確率で問題なく動作しているように見えますが、これらのエラーはランダムに発生しているように見えます。エラーが発生した場合は、通常、コードをすぐに再実行するだけで機能します。
私の目標は、このエラーを排除し、これをすべてスレッドセーフにすることです。