【发布时间】:2012-02-09 08:16:50
【问题描述】:
我正在编写一个小型 .NET(Windows 窗体)应用程序,但我似乎无法正确处理多线程。
应用程序有一个非常简单的逻辑:它显示一个主窗体,其中包含一些要填写的参数、一个开始处理的按钮和一个进度条;当用户单击按钮时开始处理,在程序运行时应该更新进度条,一些MessageBoxes可以在处理时弹出以显示警告/信息,当处理结束时另一个MessageBox会弹出结果。相当简单......但我似乎无法找到正确处理控件更新的方法。
首先我尝试了简单的路线:在 Button_Clicked 事件中进行所有处理。这并不顺利:它起作用了,但是表单在处理时变得完全没有响应,它根本不关心任何用户点击。我认为这是因为它实际上正忙于处理一个事件,因此停止处理其他事件......所以我选择了多线程。
在按钮处理事件中,我启动了一个新的Thread 并使其进行处理,然后在其上调用Thread.Join; MSDN 文档中提到了Thread.Join:“阻塞调用线程直到线程终止,同时继续执行标准 COM 和 SendMessage 泵送”(http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx)。但情况似乎并非如此:在调用Thread.Join 之后,表单再次变得无响应,直到线程终止。为什么是这样?我放弃了 Join 的想法,立即从事件处理函数中返回(禁用表单上的按钮以避免用户同时启动多个处理),但随后我遇到了另一个问题:尝试更新进度时开始出现异常栏,运行时抱怨从不是其所有者的线程调用了控件。
所以我最终选择了BackgroundWorker:我在表单中添加了一个,调用它的RunWorkerAsync() 方法并使用ReportProgress() 触发ProgressChanged 事件并在主表单中处理它(以避免交叉-线程控制更新问题)。我终于能够更新进度条了......但现在这是完全异步的:在工作线程调用ReportProgress()(甚至一秒钟!)之后,进度条实际上是在某个随机间隔更新的,这给了一个特别难看的视觉效果。两个例子:
- 如果我从工作线程调用
ReportProgress(),然后调用MessageBox.Show()以显示有关当前处理步骤的一些消息,我可以看到进度条在在 MessageBox 弹出之后前进。李> - 我有一个
RunWorkerCompleted事件,它会弹出最后一个带有结果的MessageBox,我可以看到它在屏幕上弹出而进度条仍在填充其最后一步。
我在这里错过了什么?
【问题讨论】:
-
看来,你什么都没错过。消息框是必需的吗?如果去掉,是不是也减少了丑陋?
-
是的,应用程序逻辑在处理时和结束时都需要它们。当然我可以在里面放一些
Thread.Sleep(),但这看起来真的很丑陋……
标签: .net winforms multithreading progress-bar backgroundworker