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

问题描述

| 我有一个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。 提前致谢。     

解决方法

        您必须将方法同步到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;
    }
}
    ,        您应该切换到创建该控件的线程才能与其进行交互 使用此代码可解决此问题
if(this.InvokeRequired)
   this.Invoke(new Action(() => {this.Controls.Add(linkLabel);}));
else
   this.Controls.Add(linkLabel); 
    ,        Stecya的答案也可以放入这样的扩展方法中。     ,        正如Stecya所说:您应该切换到创建该控件的线程才能与其进行交互。这可以在backgroundworkers ProgressChanged事件中完成,因为它可以在UI线程中工作,而无需执行调用。在MSDN上的样本。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...