我一直被可怕的OnUserPreferenceChanged Hang困扰,这是Ivan Krivyakov很好地引用的,这里:
http://ikriv.com/en/prog/info /dotnet/MysteriousHang.html#BeginInvokeDance
当我最初遇到问题时,我不久前发布了一个问题:
我以为我已经解决了它,方法是删除从UI线程构建的控件,但是过了一会儿它又出现了(可能再也没有出现……)。
我们一直在使用.NET 3.5,据我了解,它使用CLR 2.0.最近,该应用程序已升级为使用.NET 4.0客户端配置文件/ CLR 4.0.此外,我们已经从Infragistics winForms 10.1升级到了10.3.唯一的不同是以前的版本被混淆了...有人在混淆和挂起时遇到过问题吗?
我曾经一劳永逸地删除了所有挂起的应用程序,但不寻常的是,我无法在最新版本(使用.NET 4.0)中重现挂起.使用Ivan Krivyakov的方便的Freezer应用程序(请参阅他的文章),可以很容易地在以前的版本(使用.NET 3.5)中重现该挂起,该应用程序会根据请求触发wM_SETTINGCHANGE消息。
这个问题可能会自动消失,这让我有些希望,但是没有人知道CLR是否从2.0更改为4.0会导致此问题吗?
-----------------------------------------------------SOLUTION--------------------------------------------------
因此,在测试了应用程序的各种变化之后,例如 CLR 2.0 + Infragistics 2010.1,CLR 2.0 + Infragistics 2010.3和CLR 4.0 + Infragistics 2010.1,我们认为我们已经确定问题是winForms 2010.1中Infragistics组件的问题(无修补程序).我们仍然没有使用CLR 2.0或带有Infragistics 2010.3的CLR 4.0来复制冻结(并且我们现在非常擅长复制此冻结...)。
- 2021-1-111 #
- 2021-1-112 #
我找到了解决此问题的最佳指南:
Debugging Windows Forms Application Hangs During SystemEvents.UserPreferenceChanged - The DSUI Team Blog - Site Home - MSDN Blogs
它将逐步指导您使用winDbg验证错误的原因,并向您展示如何查找导致该错误的原因.正如您提到的,很可能是在非ui线程上创建了控件。
对于我而言,我通过创建一个工厂来解决该问题,该工厂使用UI线程中的SynchronizationContext来创建控件,然后调用CreateControl()以强制创建UI句柄。
Microsoft支持文章在这里:
Windows Forms application freezes when system settings are changed or the workstation is locked
如果您从他的网页先运行CLR 2.0然后运行CLR 4.0的示例应用程序,那么您会发现问题似乎确实在4.0中消失了-不知道发生了什么变化,但是也许他们确实解决了该问题 . BR
相关问题
- c#:NET中的锁(监控)内部实现c#netmultithreadingsynchronizationmonitor2021-01-11 23:24
- c#:获取windows 8自动颜色主题的活动颜色c#netwpfwinapiwindows82021-01-12 01:28
- c#:遍历函数结果时,foreach如何工作?c#netforeach2021-01-11 17:26
- c#:并行执行任务c#netasynchronousasyncawaittaskparallellibrary2021-01-11 04:56
- c#:静态和实例方法同名?c#netoop2021-01-11 05:55
是的,这是触发此问题的好方法.潜在的问题是由SystemEvents类引起的,它具有令人羡慕的任务:在正确的线程上引发其事件. UserPreferenceChanged事件是典型的麻烦制造者,许多控件都订阅了该事件,因此当用户更改桌面主题时它们可以重新绘制自身.组件供应商不会忽略此需求.工具箱中也没有标准的.NET框架控件。
测试此问题的一种通常不错的方法是锁定工作站(按win + L键),这也是通常在用户计算机上触发死锁的方式.切换到安全桌面倾向于触发事件.伴随着其他怪癖,当您调试程序时,这永远不会发生,并且它具有与时间相关的棘手行为,因为当没有人在机器上时,这往往会发生.尤其难以调试。
遇到这种麻烦的一种标准方法是由于程序中的初始化问题.订阅的第一个SystemEvents事件导致SystemEvents类初始化自身并设置接收这些通知并引发其相应事件所需的管道.一个自定义启动屏幕执行了太多操作(即,不仅仅是显示位图),并且在标记为STA的工作线程上运行足以解决此问题.像ProgressBar这样简单的东西就足够了. SystemEvents假定工作线程是程序的主线程,现在可以在将来轻松地在错误的线程上生成事件.有一个很好的诊断方法,如果该工作线程不再存在,则将生成优先机会异常.您可以在"输出"窗口中看到它。
或者您创建另一个UI线程并在两个线程上都有表单.不可避免地,这些形式之一总是会在错误的线程上获取事件。
唯一的体面建议是承认在工作线程上创建UI是火箭科学,微软也不知道如何正确地做.值得注意的是,.NET 1.x控件具有事件处理程序,当从错误的线程调用它时,该事件处理程序仍然可以正常工作,它仅调用Control.Invalidate().但这是在2.0时代似乎已经失去的知识,ToolStrip是一个很好的例子.并且不要相信组件供应商会正确地做到这一点,特别是Infragistics并没有出色的声誉.不要这样做。