我正在开发一个应用程序,它可以从外部服务器上获取并安装一堆更新,并且需要一些线程帮助.用户遵循以下过程:
点击按钮
方法检查更新,返回计数.
如果大于0,则询问用户是否要使用MessageBox.Show()进行安装.
如果是,则它运行循环并在每个更新的run()方法上调用BeginInvoke()以在后台运行它.
我的更新类有一些用于更新进度条等的事件.
进度条更新很好,但MessageBox未从屏幕上完全清除,因为更新循环在用户单击是后立即启动(请参见下面的屏幕截图).
在更新循环开始之前,我该怎么做才能使消息框立即消失?
我应该使用Threads而不是BeginInvoke()吗?
我应该在一个单独的线程上进行初始更新检查并从该线程调用MessageBox.Show()吗?
码
// Button clicked event handler code... DialogResult dlgRes = MessageBox.Show( string.Format("There are {0} updates available.\n\nInstall these now?", um2.Updates.Count), "Updates Available", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2 ); if (dlgRes == DialogResult.Yes) { ProcessAllUpdates(um2); } // Processes a bunch of items in a loop private void ProcessAllUpdates(UpdateManager2 um2) { for (int i = 0; i < um2.Updates.Count; i++) { Update2 update = um2.Updates[i]; ProcessSingleUpdate(update); int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count); UpdateOverallProgress(percentComplete); } } // Process a single update with IAsyncResult private void ProcessSingleUpdate(Update2 update) { update.Action.OnStart += Action_OnStart; update.Action.OnProgress += Action_OnProgress; update.Action.OnCompletion += Action_OnCompletion; //synchronous //update.Action.Run(); // async IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); }); }
截图
您的UI未更新,因为所有工作都在用户界面线程中进行.您致电:
this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); })
是说在创建"this"(你的表单)的线程上调用update.Action.Run(),这是用户界面线程.
Application.DoEvents()
确实会给UI线程重绘屏幕的机会,但我很想创建新的委托,并调用BeginInvoke.
这将在从线程池分配的单独线程上执行update.Action.Run()函数.然后,您可以继续检查IAsyncResult,直到更新完成,在每次检查后查询更新对象的进度(因为您不能让其他线程更新进度条/ UI),然后调用Application.DoEvents().
你也应该在之后调用EndInvoke(),否则你可能最终泄漏资源
我也很想在进度对话框上放置一个取消按钮,并添加超时,否则如果更新卡住(或需要太长时间),那么您的应用程序将永久锁定.