为什么系统线程.计时器回调成功更新 UI

本文关键字:成功 更新 UI 回调 计时器 系统 线程 为什么 | 更新日期: 2023-09-27 18:36:11

我的表单应用程序上有几个System.Threading.Timers,带有更新UI的回调...成功 - 即没有抛出错误。

在我知道 UI 不应该在 UI 线程以外的任何线程上更新之前,我之前就已经构建了这些。

现在我很困惑为什么当我在这些单独的线程.timer 线程上更新 UI 时它不会引发跨线程异常?

我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。

编辑:我的应用程序是WinForms应用程序。

为什么系统线程.计时器回调成功更新 UI

我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。

如果这是Windows窗体,它纯粹靠运气工作。 在后台线程上更新 UI 不会始终有效,但有时不会引发。 特别是,如果CheckForIllegalCrossThreadCalls是假的,它有时会"工作",并且永远不会抛出 - 尽管行为通常是错误的。 某些控件并不总是检查每个属性,因此某些项"工作",即使它们并不总是正常工作,因为这通常会引入以后难以诊断和更正的 bug。

附带说明:如果这是 WPF,则可以在后台线程上更改绑定到 UI 的项的值,从而有效地更新 UI。 WPF 绑定系统会自动将其封送到 UI 线程。 但是,更改集合的一部分不起作用。

我也在WinForms上经历过这种情况。请参阅此处:您可以从另一个线程访问 UI 元素吗?(未设置)在我看来,它通过"魔术"("以随机方式"阅读)起作用,不应被视为在实践中这样做的邀请。这绝不是更新 GUI 的线程安全方式。有时程序只是不抱怨。

在 .NET 1.0 和 1.1 中,不执行跨线程检查,因此永远不会得到InvalidOperationException(尽管 MSDN 承认执行跨线程更新"通常会导致不可预知的结果",其中可能包括应用程序崩溃)。

在 .NET 2.0 及更高版本中,根据 Control.CheckForIllegalCrossThreadCalls 静态属性的值执行跨线程检查。其默认值从 Debugger.IsAttached 静态属性(指示调试器是否已附加到进程)初始化,这意味着当应用程序自行运行时(未附加 Visual Studio 或任何其他调试器),不会执行跨线程检查。

当然,此设置可能会被用户代码(包括引用的库)覆盖。

我相信

这与你正在创建的定时器类型有关。有两种类型:

    System.Timers.Timer;
    System.Windows.Forms.Timer 

这两者之间有明显的区别,如果您更新UI,System.Timers.Timer 将引发异常,而 System.Windows.Forms.Timer 不会。 如果你有一个 using 语句:"Using System.Windows.Forms",并且只有一个"Timer",这将是 Windows.Forms.Timer ,它与 System.Timers.Timer 明显不同。

在引擎盖下(我相信)System.Windows.Forms.Timer 正在捕获WM_TIMER消息,因此您在更新 GUI 的线程上。