簡體   English   中英

Windows窗體:UI線程與Show()和ShowDialog()一起流動

[英]Windows Forms: UI threads flow with Show() and ShowDialog()

在Windows Forms上開發解決方案時,我進入了向用戶展示持續進展的例程。 我實現了帶有連續進度條的簡單虛擬窗口:

繼續進度窗口

在解決方案樹中,它與主窗口位於同一級別:

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無法調用它來關閉對話框。

什么是讓它按需工作的最簡單的解決方案?

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

你有一個簡單的雞蛋問題,你不會在對話關閉之后啟動工作人員。 ShowDialog()是一個阻塞調用。 因此,RunWorkerCompleted事件不會觸發,因為worker沒有啟動。 最簡單的解決方法是交換兩個語句:

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

這樣做並不完全安全。 這段代碼不是問題,但在實際代碼中,工作人員顯示對話框之前就有一個危險。 賠率低但不是零。 要解決這個問題,您需要延遲工作人員,直到您確定對話框已啟動並運行。 這可以通過對話框的OnShown()方法使用Set()的AutoResetEvent來完成。 或者,更優雅地,通過利用一個技巧:

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

當程序重新進入消息循環時,Control.BeginInvoke()的委托目標將運行。 對話框變得可見后會發生這種情況:)

這里的問題是你在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);

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM