在 Parallel.ForEach 循环中实例化用户控件
本文关键字:实例化 用户 控件 循环 Parallel ForEach | 更新日期: 2023-09-27 18:37:28
在我的应用程序中,我有一个新的Windows窗体(称为监视器),它基本上由一个大显示器(这是一个自定义用户控件)组成,它本身由许多排列在网格中的小图表(也是用户控件)组成。 当我实例化监视器窗体时,将创建一个新的显示对象,然后继续创建一堆图表控件。 然后将图表控件添加到"display"的控件集合(Controls.Add(chart)
),完成显示的加载,然后将显示添加到"监视器"的控件集合中,并显示窗体。
我遇到的问题是每个图表控件加载大约需要 0.5 秒,而我们可以在一个显示对象中拥有大约 75 个图表控件。 因此,我想并行创建这些图表,以加快加载时间。 我利用 TPL 方法Parallel.ForEach
来实现这一点。
我的代码看起来像这样,在"display"对象的构造函数中:
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.Show()
显示监视器,这只是Form
类的Show
方法。
我遇到的主要问题是 DisplayControl 构造函数偶尔会在this.Controls.Add
行抛出InvalidOperationException
,引用以下内容:
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% 的时间内工作正常,这些错误似乎是随机的。 如果我收到错误,我通常可以立即重新运行代码,它就会起作用。
我的目标是消除此错误并使所有线程安全。
所有关于System.Windows.Forms
的操作都必须在主线程中执行。关于这一点有很多问题;就像这里。因此,如果您只是在并行循环中创建图表,那么最好将其保留为普通foreach
。