为什么System.Threading.Timer回调成功更新UI?

时间:2012-06-04 16:31:26

标签: c# winforms multithreading thread-safety

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

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

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

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

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

4 个答案:

答案 0 :(得分:2)

  

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

如果这是Windows Forms,它纯粹是运气。在后台线程上更新UI并不一致,但偶尔也不会抛出。特别是,如果CheckForIllegalCrossThreadCalls为假,它有时会“起作用”,并且永远不会抛出 - 尽管行为通常是错误的。有些控件并不总是检查每个属性,因此有些项目“工作”,即使它们并不总是正常工作,因为这通常会引入以后很难诊断和纠正的错误。

旁注:如果这是WPF,您可以在后台线程上更改绑定到UI的项的值,从而有效地更新UI。 WPF绑定系统将自动将其封送到UI线程。但是,它不能改变集合的一部分。

答案 1 :(得分:1)

我也经历过WinForms。请参阅此处:Can you access UI elements from another thread? (get not set)在我看来,它以“魔术”(以“随机方式”阅读)的方式工作,不应被视为在实践中这样做的邀请。它绝不是一种更新GUI的线程安全方式。有时程序不会抱怨。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

我认为这与你正在创建什么类型的Timer有关。有两种类型:

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

这两者之间存在明显差异,如果更新UI,System.Timers.Timer将抛出异常,而System.Windows.Forms.Timer则不会。如果你有一个using语句:“使用System.Windows.Forms”并且只有一个“Timer”,这将是Windows.Forms.Timer,它与System.Timers.Timer明显不同。

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