Compact Framework/Threading - 选择选项后,MessageBox 显示在其他控件之上

Posted

技术标签:

【中文标题】Compact Framework/Threading - 选择选项后,MessageBox 显示在其他控件之上【英文标题】:Compact Framework/Threading - MessageBox displays over other controls after option is chosen 【发布时间】:2010-09-05 19:42:50 【问题描述】:

我正在开发一个应用程序,该应用程序从外部服务器获取并安装大量更新,并且需要一些线程方面的帮助。用户遵循这个过程:

点击按钮 方法检查更新,返回计数。 如果大于 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(); );

截图

【问题讨论】:

【参考方案1】:

你试过放一个

Application.DoEvents()

在这里

if (dlgRes == DialogResult.Yes)

   Application.DoEvents(); 
   ProcessAllUpdates(um2); 

【讨论】:

【参考方案2】:

您的 UI 没有更新,因为所有工作都在用户界面线程中进行。 您的电话:

this.BeginInvoke((MethodInvoker)delegate() update.Action.Run(); ) 

是说在创建“this”(您的表单)的线程上调用 update.Action.Run(),它是用户界面线程。

Application.DoEvents()

确实会给 UI 线程重绘屏幕的机会,但我很想创建新的委托,并在上面调用 BeginInvoke。

这将在从线程池分配的单独线程上执行 update.Action.Run() 函数。然后您可以继续检查 IAsyncResult 直到更新完成,在每次检查后查询更新对象的进度(因为您不能让其他线程更新进度条/UI),然后调用 Application.DoEvents()。

你也应该在之后调用 EndInvoke() 否则你最终可能会泄漏资源

我也很想在进度对话框上放置一个取消按钮,并添加一个超时,否则如果更新卡住(或花费太长时间),那么您的应用程序将永远锁定。

【讨论】:

【参考方案3】:

@约翰·西布利

You can get away with not calling EndInvoke when dealing with WinForms without any negative consequences.

我知道的唯一记录在案的规则例外是在 Windows 窗体中,正式允许您调用 Control.BeginInvoke 而无需费心调用 Control.EndInvoke。

但是,在处理 Begin/End Async 模式的所有其他情况下,您应该假设它会泄漏,正如您所说的那样。

【讨论】:

以上是关于Compact Framework/Threading - 选择选项后,MessageBox 显示在其他控件之上的主要内容,如果未能解决你的问题,请参考以下文章

PHP compact() 函数

mongodb集合批量执行compact

mongodb集合批量执行compact

mongodb集合批量执行compact

mongodb集合批量执行compact

sqlceengine.compact 方法替代