onuserpreferencechanged hang – 处理多个表单和mutlipe ui线程

我认为我的问题类似于:

.NET 4.0和可怕的OnUserPreferenceChanged Hang

我也看了看:

http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html#BeginInvokeDance

我删除了我们的启动画面。

我还尝试添加建议的代码:Microsoft.Win32.SystemEvents.UserPreferenceChanged + = delegate {}; 到我们的main()方法。

我正在寻找有关如何排除故障的一些想法和信息。

对于我们的main()方法,我们启动一个windowmanager类,它是一个使用Application.Run的表单。它只是任务栏中的一个图标(我们不显示窗口)。

每当我们启动一个对象时,我们都有一个后台线程,它创建一个表单,然后执行Application.Run(form)

在Application.Run(form)form.IsHandleCreated = false时。

我使用MysteriousHang网站上的冰箱应用程序。 (我修改它以继续在循环中发送更改通知)。

我应该如何处理创建和运行新表单? 是否在后台线程上创建表单是否重要,即使它的句柄尚未创建?

我也对术语“UI线程”感到困惑。

UI线程是一个泵送消息循环的线程。 并且以与用户界面对象兼容的模式运行,它需要是STA,单线程公寓。 这是一个COM实现细节,对于非线程安全且需要STA的常见UI操作非常重要,例如Drag + Drop,剪贴板,OpenFileDialog和ActiveX组件等shell对话框。

调用CoInitializeEx()并选择公寓类型是CLR的工作。 它由程序中Main()入口点的[STAThread]属性引导。 出现在创建UI对象(如Winforms或WPF应用程序)的项目中。 但不是控制台模式的应用程序或服务。 对于工作线程,换句话说是由代码而不是Windows创建的线程,公寓类型由您传递给Thread.SetApartmentState()方法的内容选择。 默认是MTA,错误的味道。 线程池线程始终是MTA,无法更改。

SystemEvents类有一个不值得羡慕的任务,即确定哪个线程是程序中的UI线程。 重要的是它可以在正确的线程上引发事件。 它通过使用启发式来实现,第一个订阅事件并且是STA线程的线程被认为是合适的。

当猜测不准确时,事情会出错。 或者在您尝试创建多个创建UI对象的线程的情况下,猜测对于其中一个只能是正确的。 您可能也忘了调用Thread.SetApartmentState(),因此对于它们中的任何一个都不正确。 WPF更强烈地声明这一点,并且当线程不是STA时将生成exception。

UserPreferenceChanged事件是一个麻烦制造者,它由您在工具箱上找到的一些控件订阅。 他们使用它来知道活动的视觉风格主题已经改变,因此他们将使用新的主题颜色重新绘制自己。 某些控件中事件处理程序的一个重要缺陷是它们假定事件是在正确的线程上引发的,该线程与创建控件对象的线程相同。

在您的计划中不会出现这种情况。 结果往往令人不愉快,微妙的绘画问题是一个小缺陷,僵局肯定是可能的。 出于某种原因,使用Windows + L锁定工作站并解锁它特别容易导致死锁。 在这种情况下会引发UserPreferenceChanged事件,因为桌面从用户桌面的安全桌面切换。

侦听UserPreferenceChanged事件并且使用安全线程实践(使用Control.BeginInvoke)的控件是DataGridView,NumericUpDown,DomainUpDown,ToolStrip + MenuStrip和ToolStripItem派生类,可能是RichTextBox和ProgressBar(不清楚)。

消息应该是清楚的,你使用不安全的线程实践,他们可以字节。 通常,在工作线程上创建UI永远不会有任何意义,Winforms或WPF程序的主线程已经能够支持多个窗口。 避免危险控制,这是你应该努力摆脱问题。