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

3

我有一个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;
      }

但是,当我将这段代码片段移动到 backgroundworkerdoWork 方法中时,它会在这一行出现与跨线程问题相关的无效操作异常:-this.Controls.Add(linkLabel);

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

4个回答

6

为了与控件交互,您应该切换到创建该控件的线程。

使用以下代码来解决此问题

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

2
我会使用整个方法调用invoke,因为你的示例会导致十次对Control.Invoke的调用,而不是一次。 - Florian Greinacher
这是一个优化问题。你说得对,需要避免多次调用。 - Stecya

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;
    }
}

嗨,弗洛里安,这行代码 'Invoke(AddLinkLabels);' 报错说参数无效。你有什么想法吗?谢谢。 - Gihan Anuruddha

1

0
如Stecya所说:为了与控件交互,您应该切换到创建该控件的线程。这可以在BackgroundWorker的ProgressChanged事件中完成,因为它在UI线程中工作,无需执行调用操作。示例请参见MSDN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接