【问题标题】:Update GUI from worker thread works (WinForms), why?从工作线程更新 GUI 工作(WinForms),为什么?
【发布时间】:2019-12-11 14:43:08
【问题描述】:

WinForms (VS2015 / .NET 4.6)

在我的后台线程中

 System.Threading.Tasks.Task.Run(() =>
 {
    ...
    _callback?.Progress("abcd");
    ...
 });

我调用 GUI (_callback),它在 Form 类中实现了一个接口。 在这里,我修改了文本框、进度条等值。

void IWorkerCallback.Log(string message)
{
    _textBoxLog.AppendText($"{message}{Environment.NewLine}");
    ++_progressBar.Value;
    .... etc...
}

一切正常!
如果我使用调试器,我可以看到Form.IWorkerCallback.Log() 函数在工作线程上下文中执行(在线程调试窗口中)。

到处都说您必须仅在 GUI 线程(创建它们的位置)上更改 GUI 项目,否则您会得到 System.InvalidOperationException 异常 cross-thread operation not valid.....

但这对我来说很好用。

你能解释一下,为什么?

谢谢

【问题讨论】:

  • 这是未定义的行为。它可能有效,也可能无效。要在跨线程调用上获得一致的失败,请在程序开头设置Control.CheckForIllegalCrossThreadCalls = true
  • docs.microsoft.com/en-us/dotnet/api/… 在较低的 Windows API 级别上,不使用线程本地存储或任何其他线程特定资源的跨线程 UI 调用可能会成功执行。
  • @AlexF - 是的,就是这样,Control.CheckForIllegalCrossThreadCalls 是诀窍!如果你把它写成答案,我会接受它。
  • 这就是BeginInvoke() 的用途。它可以从不同的线程或主线程调用。您无需查看InvokeRequired。无需考虑是否附加了调试器。
  • 是的,我知道,但很惊讶它可以在没有 begininvoke() 的情况下工作

标签: multithreading winforms controls


【解决方案1】:

从另一个线程运行 UI 调用是未定义的行为。它可能有效,也可能无效。要在程序开始时设置Control.CheckForIllegalCrossThreadCalls = true; 的跨线程调用失败:

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.checkforillegalcrossthreadcalls?view=netframework-4.8

来自 MSDN 文档:

当控件的创建线程以外的线程尝试访问该控件的方法或属性之一时,通常会导致不可预知的结果。常见的无效线程活动是对访问控件的 Handle 属性的错误线程的调用。将 CheckForIllegalCrossThreadCalls 设置为 true 可以更轻松地查找和诊断此线程活动。

在低 Windows API 级别上,不使用线程本地存储或任何其他线程特定资源的跨线程 UI 调用可能会成功执行。但是,我们仍然有线程同步问题,所以结果也是未定义的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-13
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    相关资源
    最近更新 更多