我的应用程序在很大程度上依赖线程来处理非常大的数据。在处理完成时,需要更新UI。我知道并尝试使用BackgroundWorker's
OnProgressChanged
和RunWorkerCompleted
方法来更新UI。还使用UI线程的Invoke
方法进行更新。在Win XP 32位和64位操作系统上,一切似乎都能正常工作。在Win Vista和Win 7(32位和64位)上,应用程序在使用Invoke
方法更新UI时随机挂起。
Invoke
的行为是否会在不同的Win OS上发生变化?
除了Invoke
之外,还有哪些其他方法可以从线程更新UI?
由于
答案 0 :(得分:2)
不确定出现了什么问题,但您可以随时运行System.Windows.Forms.Timer
来定期更新GUI;如果需要,使用一些成员变量在线程之间传递原始数据。这不是最优雅的解决方案,但它可能会让您对悬挂的内容有不同的看法,因为线程更加独立,而不是依赖于后台线程Invoke
主线程。
答案 1 :(得分:2)
Invoke的行为是否会在不同的Win OS上发生变化?
不应该,不。但是,线程问题可能以非常不可预测的方式实现。你可能有一个身份不明的问题。
除了Invoke之外,还有什么方法可以从线程更新UI?
使用Invoke
或BeginInvoke
过度使用,尤其是在尝试向UI线程报告简单的进度信息时。如果您搜索我与该主题相关的一些答案,您将看到我一直在抨击这种方法。并且有充分的理由,因为它们使用这种技术有许多缺点。遗憾的是,BackgroundWorker
仅使用此机制通过其ProgressChanged
事件更新UI。
另一种方法是让您的工作线程将进度信息发布到共享变量中,并通过计时器定期对其进行UI线程轮询。以下是我通常的谈话要点,以证明这种方法优于编组技术。
Invoke
和BeginInvoke
是昂贵的操作。ISynchronizeInvoke
强加的UI和工作线程之间的紧密耦合。Invoke
那样等待响应。答案 2 :(得分:1)
您可以尝试使用Disokecher.Priority枚举作为参数的Invoke()或BeginInvoke()重载之一。如果您选择“背景”等参数,您应该会看到您的应用程序仍然具有响应性。然后,唯一的问题就是确保您以足够的速度为传入数据提供服务,而不会增加队列。
答案 3 :(得分:0)
另一种选择是完全放弃多线程。如果长时间运行的操作可以分解为块,请在GUI线程中执行,并在需要更新GUI时使用Application.DoEvents()
。
我曾经不喜欢使用该方法,因为它不仅可以更新GUI,还可以开始响应用户输入,启动计时器等,但最终它的安全性并不比使用后台线程更安全,后者允许GUI随时开始做任何事情。因此,在每次调用Application.DoEvents()
之后,您可能需要检查_canceled
或其他任何内容。 (我最终决定不喜欢这种方法的存在,因为它消除了线性执行顺序的保证,而不是使用它。)
当然,您会以这种方式失去多核支持,因此如果您尝试同时运行大量后台操作,则会影响性能。