C# Compact Framework/Threading-选择此选项后,MessageBox将显示在其他控件上

C# Compact Framework/Threading-选择此选项后,MessageBox将显示在其他控件上,c#,winforms,multithreading,compact-framework,C#,Winforms,Multithreading,Compact Framework,我正在开发一个应用程序,它从外部服务器上获取并安装一系列更新,需要一些线程方面的帮助。用户遵循以下过程: 点击按钮 方法检查更新,返回计数 如果大于0,则询问用户是否要使用MessageBox.Show()进行安装 如果是,它将通过一个循环运行,并在每次更新的run()方法上调用BeginInvoke(),以便在后台运行它 我的更新类有一些用于更新进度条等的事件 进度条更新正常,但MessageBox没有完全从屏幕上清除,因为更新循环在用户单击yes(是)后立即启动(请参见下面的屏幕截图)

我正在开发一个应用程序,它从外部服务器上获取并安装一系列更新,需要一些线程方面的帮助。用户遵循以下过程:

  • 点击按钮
  • 方法检查更新,返回计数
  • 如果大于0,则询问用户是否要使用MessageBox.Show()进行安装
  • 如果是,它将通过一个循环运行,并在每次更新的run()方法上调用BeginInvoke(),以便在后台运行它
  • 我的更新类有一些用于更新进度条等的事件
进度条更新正常,但MessageBox没有完全从屏幕上清除,因为更新循环在用户单击yes(是)后立即启动(请参见下面的屏幕截图)

  • 在更新循环开始之前,我应该如何使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(); });
}
//按钮已单击事件处理程序代码。。。
DialogResult dlgRes=MessageBox.Show(
string.Format(“有{0}个更新可用。\n\n现在安装吗?”,
um2.Updates.Count),“更新可用”,
MessageBoxButtons.YesNo,
MessageBoxIcon.问题,
MessageBoxDefaultButton.Button2
);
如果(dlgRes==DialogResult.Yes)
{
过程更新(um2);
}
//在循环中处理一组项
私有void进程更新(UpdateManager 2 um2)
{
对于(int i=0;i
屏幕截图


你试过把

Application.DoEvents()
在这里

if (dlgRes == DialogResult.Yes)
{
   Application.DoEvents(); 
   ProcessAllUpdates(um2); 
}

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

this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 
在创建“this”(您的表单)的线程上调用update.Action.Run(),该线程是用户界面线程

Application.DoEvents()
确实会给UI线程重新绘制屏幕的机会,但我会尝试创建新的委托,并就此调用BeginInvoke

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

您还应该在之后调用EndInvoke(),否则可能会导致资源泄漏

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

@John Sibly

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

然而,在处理Begin/End异步模式的所有其他情况下,您应该假设它会泄漏,正如您所说的