如何从后台线程修改控件属性,而不使用Control.Invoke() [英] How can a control property be modified from background thread without Control.Invoke()

查看:150
本文介绍了如何从后台线程修改控件属性,而不使用Control.Invoke()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我们遇到了,我们需要用一些新的功能更新一些旧的WinForms应用程序。虽然专家测试应用程序,人们发现,一些老的功能被打破。无效的跨线程操作。现在,你把我当菜鸟之前,我也有一些经验与Windows窗体应用程序。我不是专家,但我认为自己经历了线程和确切地知道如何从一个工作线程操作GUI组件。

Recently we came across some legacy WinForms application we needed to update with some new features. While expert testing the application, it was found that some old functionality is broken. Invalid cross-thread operation. Now before you take me for a newbie, I do have some experience with Windows Forms applications. I'm no expert, but I consider myself experienced with threading and know exactly how to manipulate GUI components from a worker thread.

显然,谁写这个软件的一个没,只是从后台线程设置UI控件属性。当然它扔了通常例外,但它是在一个全醒目try-catch块包裹。

Apparently the one who wrote this piece of software did not and just set UI control properties from a background thread. Of course it threw the usual exception, but it was encased in an all-catching try-catch block.

我跟一个利益相关者说话,找出这个功能了多久被打破,原来之前的罚款。我简直不敢相信,但他演示了我,函数实际上工作在PROD。

I spoke with a stakeholder to find out how long this functionality had been broken, and turned out it was fine before. I couldn't believe that, but he demoed me that the function actually works in PROD.

因此,我们不相关的更新在三个地方爆料的软件,但我可以'T让我的头围绕它如何能在第一时间已经奏效。据源头控制,错误一直存在。

So our unrelated updates "broke" the software in three places, but I can't get my head around how it could have worked in the first place. According to source control, the bug has always been there.

当然,我们更新了适当的跨线程UI处理逻辑的应用,但现在我在倒霉其位置,直到我们做对系统一些无关的变化没有太大的技术背景来解释为什么利益相关者的东西,不能有像工作过,做过做工精细。

Of course we updated the application with proper cross-thread UI handling logic, but now I'm in the unlucky position of having to explain to stakeholders with not much tech background why something that can't have worked like ever, did work fine until we did some unrelated changes to the system.

任何见解将不胜感激。

来考虑一件事:两个案件的后台线程更新,这是一个ListView控件非选择(因此非显示)TabPage的控制。这最初是空的,它是标准的Label控件(文本属性设置)第三次获得根据后台线程发现什么分配文本。

One more thing that came to mind: in two of the cases the background thread updated a ListView control that was on a non-selected (and thus non-displayed) TabPage control. The third time it was standard Label control (text property was set) that was initially empty and gets a Text assigned according to what the background thread finds.

下面是一些代码你,非常相似,我们发现之一:

Here's some code for you, very similar to the one we found:

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在生产环境中被更新,它不会从其他地方在整个应用程序引用(除了设计器生成的东西,当然)。

Unfortunately I saw lblStatus being updated in the production environment and it isn't referenced from anywhere else in the entire application (except the Designer generated stuff, of course).

推荐答案

这是因为跨线程访问异常,不能保证当你没有调试器中运行代码(在Windows窗体)被抛出。阅读此例如: https://开头msdn.microsoft.com/en-us/library/vstudio/ms171728%28v=vs.110%29.aspx

That is because cross-thread access exceptions are not guaranteed to be thrown when you run code without debugger (in windows forms). Read this for example: https://msdn.microsoft.com/en-us/library/vstudio/ms171728%28v=vs.110%29.aspx:

.NET框架帮助时,您正在访问在不是线程安全的方式,您的控件您检测。当您运行在调试器应用程序,并且比它创造了一个控制试图调用该控件的另一个线程,调试器引发一个InvalidOperationException的消息,控制从比它的线程是其他线程访问控件名称创建了

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."

这异常调试过程中发生可靠,并在某些情况下,在运行时。当你调试你之前在.NET Framework 2.0 .NET Framework中写道应用程序,您可能会看到这个异常。我们强烈建议你当你看到它来解决这个问题,但你可以通过CheckForIllegalCrossThreadCalls属性设置为false禁用它。这将导致你的控制运行像它会在Visual Studio .NET 2003中和.NET Framework 1.1上运行。

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应用程序,从另一个线程设置窗体标题,看到异常。然后运行相同的应用程序,而调试器附加,看看窗体标题会很乐意改变,没有任何问题。

You can check this yourself by writing simple winforms application, set form title from another thread and see exception is thrown. Then run same application without debugger attach and see how form title will happily change without any problems.

这篇关于如何从后台线程修改控件属性,而不使用Control.Invoke()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆