CodeGo.net>如何在没有Control.Invoke()的情况下从后台线程修改控件属性

最近,我们遇到了一些旧版WinForms应用程序,我们需要使用一些新功能对其进行更新.在专家测试应用程序时,发现某些旧功能已损坏.无效的跨线程操作.现在,在您带我去做新手之前,我确实对Windows Forms应用程序有一些经验.我不是专家,但是我认为自己有线程方面的经验,并且确切地知道如何从工作线程中操纵GUI组件.

显然,编写此软件的人并没有从后台线程设置UI控件属性.当然,它引发了通常的异常,但是它被装入了一个全捕获的try-catch块中.

我与利益相关者进行了交谈,以了解该功能被破坏了多长时间,结果证明以前还不错.我简直不敢相信,但他向我演示了该功能实际上在PROD中有效.

因此,我们无关的更新在三个地方“破坏”了该软件,但是我无法一开始就了解它是如何工作的.根据源代码控制,该漏洞一直存在.

当然,我们使用适当的跨线程UI处理逻辑对应用程序进行了更新,但是现在我很不幸地不得不向没有太多技术背景的利益相关者解释为什么某些东西无法像以往那样正常工作直到我们对系统做了一些无关的更改.

任何见解将不胜感激.

我想到的另一件事:在两种情况下,后台线程更新了未选择(因此未显示)的TabPage控件上的ListView控件.第三次是标准Label控件(设置了text属性),该控件最初为空,并根据后台线程找到的内容分配了Text.

这是一些适合您的代码,与我们找到的代码非常相似:

private void form_Load(object sender, System.EventArgs e)
{
  // unrelated stuff...
  ThreadStart ts = new ThreadStart(this.doWork);
  Thread oThread = new Thread(ts);
  ts.Start();
  // more unrelated stuff ...
}

public void doWork()
{
  string error = string.Empty;
  int result = 0;
  try
  {
    result = this.service.WhatsTheStatus(out error); // lengthy operation
    switch (result)
    {
      case 1:
        this.lblStatus.Text = "OK";
        break;
      case -1:
        this.lblStatus.Text = "Error";
        this.lblError.Text = error;
        break;
      default:
        this.lblStatus.Text = "Unknown";
        break;
    }
  }
  catch
  {
  }
}

不幸的是,我看到lblStatus在生产环境中进行了更新,并且没有在整个应用程序的其他任何地方引用它(当然,除了Designer生成的东西之外).

解决方法:

这是因为在没有调试器的情况下(在Windows窗体中)运行代码时,不能保证会引发跨线程访问异常.例如阅读:https://msdn.microsoft.com/en-us/library/vstudio/ms171728%28v=vs.110%29.aspx

The .NET Framework helps you detect when you are accessing your controls in a manner that is not thread safe. When you are running your application in the debugger, and a thread other than the one which created a control tries to call that control, the debugger raises an InvalidOperationException with the message, “Control control name accessed from a thread other than the thread it was created on.”

This exception occurs reliably during debugging and, under some circumstances, at run time. You might see this exception when you debug applications that you wrote with the .NET Framework prior to the .NET Framework 2.0. You are strongly advised to fix this problem when you see it, but you can disable it by setting the CheckForIllegalCrossThreadCalls property to false. This causes your control to run like it would run under Visual Studio .NET 2003 and the .NET Framework 1.1.

您可以通过编写简单的winforms应用程序自己检查此问题,从另一个线程设置表单标题并查看是否引发了异常.然后在没有调试器附加的情况下运行同一应用程序,并查看表单标题将如何愉快地更改而不会出现任何问题.

上一篇:C#-GUI消息队列(消息泵-并行或串行)


下一篇:C#如何将字符追加到列表框DisplayMember?