如何以线程安全的方式更新控件

时间:2011-05-30 10:41:45

标签: c# winforms visual-studio-2010 thread-safety backgroundworker

我有一个windows.form.userControl类,在运行时我想动态添加一些链接标签。当我在Load方法中应用此代码片段时,它完美地工作。

for (int i = 0; i < 10; i++)
     {
       linkLabel = new System.Windows.Forms.LinkLabel();
       linkLabel.Name = i.ToString();
       linkLabel.Text = i.ToString();
       linkLabel.LinkClicked += new  System.Windows.Forms.LinkLabelLinkClickedEventHandler(linkLabel_LinkClicked);
       this.Controls.Add(linkLabel);
       linkLabel.Top = top;
       top += 30;
      }

但是当我将此代码段移到 backgroudworker doWork 方法时,它会给出无效的操作异常在这一行中交叉线程问题: - this.Controls.Add(linkLabel);

如何将其作为线程安全操作?我是C#的新手,我正在使用VS 2010使用C#4.0。 提前谢谢。

4 个答案:

答案 0 :(得分:6)

您应切换到创建该控件的线程以便与其进行交互

使用此代码修复此

if(this.InvokeRequired)
   this.Invoke(new Action(() => {this.Controls.Add(linkLabel);}));
else
   this.Controls.Add(linkLabel); 

答案 1 :(得分:3)

您必须将方法同步到UI线程。您可以使用属性Control.InvokeRequired检查是否需要同步,并Control.Invoke同步调用任何委托。

private void AddLinkLabels()
{
    // If synchronization is needed, i.e. when this method is called on a non-UI thread, invoke the method synchronized and return immediately.
    if(InvokeRequired)
    {
        Invoke(new MethodInvoker(AddLinkLabels));
        return;
    }

    for (int i = 0; i < 10; i++)
    {
        linkLabel = new System.Windows.Forms.LinkLabel();
        linkLabel.Name = i.ToString();
        linkLabel.Text = i.ToString();
        linkLabel.LinkClicked += new  System.Windows.Forms.LinkLabelLinkClickedEventHandler(linkLabel_LinkClicked);
        this.Controls.Add(linkLabel);
        linkLabel.Top = top;
        top += 30;
    }
}

答案 2 :(得分:1)

Stecya的答案也可以放入an extension method like this

答案 3 :(得分:0)

正如Stecya已经说过:你应该切换到创建该控件的线程以便与之交互。这可以在backgroundworkers ProgressChanged事件中完成,因为它在UI线程中工作,而不需要调用。以MSDN为样本。