gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 16:06:10 24 4
gpt4 key购买 nike

最近我们遇到了一些遗留的 WinForms 应用程序,我们需要更新一些新功能。在专家测试该应用程序时,发现一些旧功能已损坏。无效的跨线程操作。现在,在您把我当作新手之前,我确实有一些 Windows 窗体应用程序的经验。我不是专家,但我认为自己在线程方面很有经验,并且确切地知道如何从工作线程操作 GUI 组件。

显然,编写此软件的人并没有这样做,只是从后台线程设置 UI 控件属性。当然,它抛出了通常的异常,但它被包裹在一个万能的 try-catch block 中。

我与一位利益相关者进行了交谈,以了解此功能被破坏了多长时间,结果证明它之前没有问题。我简直不敢相信,但他向我演示了该功能在 PROD 中确实有效。

因此,我们不相关的更新在三个地方“破坏”了软件,但我无法理解它最初是如何工作的。根据源代码控制,错误一直存在。

当然,我们使用适当的跨线程 UI 处理逻辑更新了应用程序,但现在我很不幸,不得不向技术背景不多的利益相关者解释为什么某些东西不能像以前那样工作,确实在我们对系统进行一些不相关的更改之前工作正常。

如有任何见解,我们将不胜感激。

还有一件事浮现在脑海中:在两种情况下,后台线程更新了一个 ListView 控件,该控件位于未选择(因此未显示)的 TabPage 控件上。第三次是标准的 Label 控件(设置了文本属性),它最初是空的,并根据后台线程找到的内容分配了一个文本。

这里有一些代码,与我们找到的代码非常相似:

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# - 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32603127/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com