我的表单应用程序上有几个 System.Threading.Timers 带有更新 UI 的回调......成功 - 即没有抛出错误。
在我知道 UI 不应该在 UI 线程以外的任何线程上更新之前,我已经构建了这些。
现在我很困惑为什么当我在这些单独的 threading.timer 线程上更新 UI 时它不会引发跨线程异常?
我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。
编辑:我的应用程序是一个 WinForms 应用程序。
我的表单应用程序上有几个 System.Threading.Timers 带有更新 UI 的回调......成功 - 即没有抛出错误。
在我知道 UI 不应该在 UI 线程以外的任何线程上更新之前,我已经构建了这些。
现在我很困惑为什么当我在这些单独的 threading.timer 线程上更新 UI 时它不会引发跨线程异常?
我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。
编辑:我的应用程序是一个 WinForms 应用程序。
我将更改这些回调,以便在 UI 线程上调用 UI 更新,但我很好奇为什么会这样。
如果这是 Windows 窗体,它完全靠运气工作。在后台线程上更新 UI 并不能始终如一地工作,但偶尔不会抛出。特别是,如果CheckForIllegalCrossThreadCalls为假,它有时会“工作”,并且永远不会抛出 - 尽管行为通常是错误的。一些控件并不总是检查每个属性,因此有些项目“工作”即使它们并不总是正常工作,因为这通常会引入以后难以诊断和纠正的错误。
附带说明:如果这是 WPF,您可以在后台线程上更改绑定到 UI 的项目的值,从而有效地更新您的 UI。WPF 绑定系统会自动为您将其编组到 UI 线程。但是,更改集合的一部分不起作用。
我也使用 WinForms 体验过这一点。请参见此处:您可以从另一个线程访问 UI 元素吗?(不要设置)在我看来,它通过“魔法”(阅读“以随机方式”)起作用,不应被视为在实践中这样做的邀请。这绝不是更新 GUI 的线程安全方式。有时程序只是不抱怨。
在 .NET 1.0 和 1.1 中,不执行跨线程检查,因此您永远不会得到一个InvalidOperationException
(尽管 MSDN 承认执行跨线程更新“通常会导致不可预知的结果”,其中可能包括应用程序崩溃)。
Control.CheckForIllegalCrossThreadCalls
在 .NET 2.0 及更高版本中,根据静态属性的值执行跨线程检查。它的默认值是从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 的线程上。