【问题标题】:Windows Forms: UI threads flow with Show() and ShowDialog()Windows 窗体:UI 线程使用 Show() 和 ShowDialog() 流动
【发布时间】:2014-01-19 17:15:30
【问题描述】:

在 Windows 窗体上开发解决方案时,我进入了一个向用户显示持续进度的例程。我实现了带有连续进度条的简单虚拟窗口:

在解决方案树中,它与主窗口位于同一级别:

在做某事时显示持续进步的最简单的工作方法是以下代码。它确实有效

//This method works
private void DoSomeBackgroundStuffWithShow()
{
    ContinuousProgressWindow continuousProgressWindow = 
        new ContinuousProgressWindow();
    BackgroundWorker backgroundWorker = new BackgroundWorker();
    backgroundWorker.DoWork += (sender, arguments) =>
    {
        //Do some  stuff for 4 seconds
        Thread.Sleep(4000);
    };
    backgroundWorker.RunWorkerCompleted += (sender, arguments) =>
    {
        //Window is closed when needed. Great!
        continuousProgressWindow.Dispose(); 
    };
    continuousProgressWindow.Show(this);
    backgroundWorker.RunWorkerAsync();
}

但我需要此窗口出现在最顶部并在工作时阻止其父级。以下代码非常相似,但它不起作用 - 显示对话框,但 从未关闭

//This method DOES NOT WORK
private void DoSomeBackgroundStuffWithShowDialog()
{
    ContinuousProgressWindow continuousProgressWindow =
        new ContinuousProgressWindow();
    BackgroundWorker backgroundWorker = new BackgroundWorker();
    backgroundWorker.DoWork += (sender, arguments) =>
    {
        //Do some important stuff for 4 seconds
        Thread.Sleep(4000);
    };
    backgroundWorker.RunWorkerCompleted += (sender, arguments) =>
    {
        //None of the following work for "ShowDialog() method"
        //Ran with debugger - breakpoints not hit!
        continuousProgressWindow.DialogResult = DialogResult.OK;
        continuousProgressWindow.Close();
        continuousProgressWindow.Dispose();
    };
    continuousProgressWindow.ShowDialog(this);
    backgroundWorker.RunWorkerAsync();
}

然后,我意识到问题在于 UI 线程流:当进度窗口作为对话框运行时,MainWindow 线程被冻结,并且无法由RunWorkerCompleted 委托中的BackgroundWorker 调用以关闭对话框。

最简单的解决方案是什么?

【问题讨论】:

  • 使用 showDialog,backgroundWorker.RunWorkerAsync(); 直到 continuousProgressWindow 退出时才会被调用。您是否尝试过在显示窗口之前启动backgroundWorker
  • @StevenMills 我刚刚尝试过,它奏效了。发布带有编辑和注释代码的答案,我会接受。
  • 等待想要接受有用的答案。太多的人只是读了答案就永远消失了。

标签: c# multithreading winforms dialog .net-3.5


【解决方案1】:

这里的问题是您在 backgroundWorker.RunWorkerAsync() 之前调用了 ContinuousProgressWindow.ShowDialog(this)。因此,一旦您关闭窗口,就会调用 backgroundWorker.RunWorkerAsync()。

我认为下面的代码应该可以工作,正如@Steven Mills 所建议的那样。

private void DoSomeBackgroundStuffWithShowDialog()
{
    ContinuousProgressWindow continuousProgressWindow =
        new ContinuousProgressWindow();
    BackgroundWorker backgroundWorker = new BackgroundWorker();
    backgroundWorker.DoWork += (sender, arguments) =>
    {
        //Do some important stuff for 4 seconds
        Thread.Sleep(4000);
    };
    backgroundWorker.RunWorkerCompleted += (sender, arguments) =>
    {
        //None of the following work for "ShowDialog() method"
        //Ran with debugger - breakpoints not hit!
        continuousProgressWindow.DialogResult = DialogResult.OK;
        continuousProgressWindow.Close();
        continuousProgressWindow.Dispose();
    };

    backgroundWorker.RunWorkerAsync();
    continuousProgressWindow.ShowDialog(this);

}

【讨论】:

    【解决方案2】:
      continuousProgressWindow.ShowDialog(this);
      backgroundWorker.RunWorkerAsync();
    

    您遇到了一个简单的先有鸡还是先有蛋的问题,直到对话框关闭后 才启动worker。 ShowDialog() 是一个阻塞调用。所以 RunWorkerCompleted 事件不会触发,因为工人没有开始。最简单的解决方法是交换两个语句:

      backgroundWorker.RunWorkerAsync();
      continuousProgressWindow.ShowDialog(this);
    

    这样做并不完全安全。这个 sn-p 不是问题,但在实际代码中存在工作人员在显示对话框之前完成 的危险。赔率低但不为零。为了解决这个问题,您希望延迟工作人员,直到您确定对话框已启动并正在运行。这可以通过对话框的 OnShown() 方法使用 Set() 的 AutoResetEvent 来完成。或者,更优雅的是,利用一个技巧:

      this.BeginInvoke(new Action(() => backgroundWorker.RunWorkerAsync()));
      continuousProgressWindow.ShowDialog(this);
    

    Control.BeginInvoke() 的委托目标在程序重新进入消息循环时运行。这发生在对话框变得可见之后:)

    【讨论】:

    • 简短而有用的答案:经过测试,它可以正常工作。我在哪里可以阅读有关消息循环的这些技巧?
    • 当然是在 Stackoverflow 上 :) 这是一个古老的技巧,早在 .NET 出现之前就已经使用了。 C 程序员使用 PostMessage(),Charles Petzold 写过,C# 使代码更漂亮。
    猜你喜欢
    • 2011-02-24
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多