在Parallel.ForEach循环中实例化用户控件

时间:2013-10-30 21:03:19

标签: c# .net multithreading winforms task-parallel-library

在我的应用程序中,我有一个新的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%的时间内都能正常工作,而这些错误似乎是随机的。如果我收到错误,我通常可以立即重新运行代码,它会起作用。

我的目标是消除此错误并使其全部线程安全。

1 个答案:

答案 0 :(得分:2)

关于System.Windows.Forms的所有操作必须在主线程中执行。关于这一点有很多问题;比如here。因此,如果您只是在并行循环中创建图表,那么最好将其保持为普通foreach