在我的应用程序中,我有一个新的Windows窗体(称为监视器),它基本上由一个大显示器(一个自定义用户控件)组成,它本身由排列在网格中的许多小图表(也是用户控件)组成。当我实例化监视器窗体时,会创建一个新的显示对象,然后继续创建一组图表控件。然后将图表控件添加到“display”控件集合(Controls.Add(chart)
),完成显示的加载,然后将显示添加到“monitor”的控件集合中,并显示表单。
我遇到的问题是每个图表控件需要大约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()
显示监视器,这只是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%的时间内都能正常工作,而这些错误似乎是随机的。如果我收到错误,我通常可以立即重新运行代码,它会起作用。
我的目标是消除此错误并使其全部线程安全。
答案 0 :(得分:2)
关于System.Windows.Forms
的所有操作必须在主线程中执行。关于这一点有很多问题;比如here。因此,如果您只是在并行循环中创建图表,那么最好将其保持为普通foreach
。