使用c#中的完成消息框同步进度条“填充”

时间:2011-10-26 19:14:48

标签: c# winforms

我有一个线程处理二进制文件并将其存储在数据表中。 处理时我正在使用当前流位置更新进度条。 我的问题是;在线程中我有一个finally {}块,并且我将progressbar值设置为最大允许值,然后我运行Application.DoEvents();然后我显示一个MessageBox,但我的MessageBox总是在Progressbar填充之前出现。

problem

here is the applicable code

here is a video showing the issue

我创建了一个小应用程序来演示使用BackgroundWorker而不是Thread。 Here is the code

我看到了相同的'错误'(我犹豫不决称这是一个错误,更多的是可用性问题)正如你所看到的那样,我还在那里添加了一个 dirty 小记录器。日志文件末尾的输出是:

  

27/10/2011 4:58:29 PM - 进入进度

     

27/10/2011 4:58:29 PM - 进度已更改为79661

     

27/10/2011 4:58:29 PM - 进入进度

     

27/10/2011 4:58:29 PM - 进度已更改为79661

     

27/10/2011 4:58:29 PM - 完成输入

     

27/10/2011 4:58:29 PM - 事件完成

     

27/10/2011 4:58:30 PM - 显示消息

因此执行命令的顺序没有问题...是我在显示消息框之前添加延迟的唯一真正解决方案吗?

2 个答案:

答案 0 :(得分:5)

我会尝试用简单的Application.DoEvents();替换Thread.Sleep(100)。围绕DoEvents的文档似乎并未表明是否允许您从另一个非UI线程调用它。通过使用Thread.Sleep代替,您将延迟消息框弹出窗口并允许UI线程正常处理。

让工作者背景弹出消息框的另一种方法是使用一个事件,并在UI线程上调用已订阅的委托(就像你对进度条所做的那样)。

实际上,如果您愿意,您可以重写线程代码以使用BackgroundWorker对象,并订阅ProgressChangedRunWorkerCompleted事件。您的实际线程代码将负责调用ReportProgress方法来触发ProgressChanged事件以更新您的进度条。

对更新的响应

查看新代码后,当工人完成时,您永远不会将进度条设置为最大值。在显示消息框之前worker_RunWorkerCompleted添加progressBar1.Value = progressBar1.Maximum;。这应该在弹出消息框之前将进度条更新到最大值。

答案 1 :(得分:2)

正如Joshua建议的那样,你不能从与你的UI不同的线程调用DoEvents。因此,我(基于这个事实)建议您在线程上使用Join()方法等待(从UI线程)直到它结束。

您还可以使用ThreadDispatcher(可能仅限WPF)或使用表单上的Invoke()方法从辅助线程调用主UI线程上的方法。

修改 另一个解决方案是创建一个看起来像MessageBox的自己的表单,然后让该窗口正常显示,这样它就不会阻塞UI线程。