紧凑框架/线程 - 选择选项后消息框显示在其他控件之上
-
08-06-2019 - |
题
我正在开发一个应用程序,该应用程序可以从外部服务器获取并安装大量更新,并且需要一些线程方面的帮助。用户遵循以下流程:
- 点击按钮
- 方法检查更新,返回计数。
- 如果大于 0,则询问用户是否要使用 MessageBox.Show() 安装。
- 如果是,它会运行一个循环,并在每个更新的 run() 方法上调用 BeginInvoke() 以在后台运行它。
- 我的更新类有一些用于更新进度条等的事件。
进度条更新正常,但 MessageBox 并未从屏幕上完全清除,因为更新循环在用户单击“是”后立即开始(请参见下面的屏幕截图)。
- 我应该怎么做才能使消息框在更新循环开始之前立即消失?
- 我应该使用线程而不是 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() 否则您可能最终会泄漏资源
我还想在进度对话框上放置一个取消按钮,并添加超时,否则如果更新卡住(或花费太长时间),那么您的应用程序将永远锁定。
其他提示
你有没有尝试过放一个
Application.DoEvents()
在这里
if (dlgRes == DialogResult.Yes)
{
Application.DoEvents();
ProcessAllUpdates(um2);
}
@约翰·西布利
你可以摆脱 不是 在处理 WinForms 时调用 EndInvoke 不会产生任何负面后果。
据我所知,唯一有记录的规则例外是在 Windows 窗体中,其中正式允许您调用 Control.BeginInvoke,而不必费心调用 Control.EndInvoke。
然而,在所有其他情况下,在处理开始/结束异步模式时,您应该假设它会泄漏,正如您所说。
不隶属于 StackOverflow