2013-10-21 40 views
0

我在我的UI(WPF)線程中創建了一個BackgroundWorker(mainBw)。它有一個無限循環,睡眠時間爲1.5秒,通過Application.Current.Dispatcher.Invoke調用一個函數,該函數只將文​​本從「global」text變量輸出到TextBox。.NET BackgroundWorker:我不明白ReportProgress是如何工作的

還在循環之前它創建了另一個(child)BackgroundWorker其中ReportsProgress在ProgressChanged事件處理程序中修改text變量。

我以爲它不會工作,因爲沒有任何像WinForms Application.DoEvents()mainBw循環中的任何東西,所以它無法處理事件處理程序。但它的工作。爲什麼?

下面是代碼:

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows; 

namespace WpfApplication6 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private BackgroundWorker mainBw = new BackgroundWorker(); 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      mainBw.DoWork += MainBwOnDoWork; 

      mainBw.RunWorkerAsync(); 

      btn.IsEnabled = false; 
     } 

     private string text = "abc"; 

     private void MainBwOnDoWork(object sender, DoWorkEventArgs e) 
     { 
      BackgroundWorker bw = new BackgroundWorker(); 

      bw.DoWork += BwOnDoWork; 
      bw.ProgressChanged += BwOnProgressChanged; 
      bw.WorkerReportsProgress = true; 

      bw.RunWorkerAsync(); 

      while (true) 
      { 
       Thread.Sleep(1500); 

       text += " main "; 

       Application.Current.Dispatcher.Invoke(new Action(() => { WriteToUIThread(); })); 
      } 
     } 

     private void WriteToUIThread() 
     { 
      tbox.Text = DateTime.Now + " " + text + Environment.NewLine + tbox.Text; 
     } 

     private void BwOnProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      text += e.UserState.ToString(); 
     } 

     private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) 
     { 
      while (true) 
      { 
       Thread.Sleep(3000); 

       (sender as BackgroundWorker).ReportProgress(0, "child"); 
      } 

     } 
    } 
} 

    // XAML 
<Window x:Class="WpfApplication6.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Button Name="btn" Content="Button" HorizontalAlignment="Left" Height="105" Margin="43,47,0,0" VerticalAlignment="Top" Width="165" Click="Button_Click"/> 
     <TextBox Name="tbox" HorizontalAlignment="Left" Height="114" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="456" Margin="27,182,0,0"/> 
    </Grid> 
</Window> 
+0

因爲UI線程未被鎖定。一旦'BwOnProgressChanged'函數完成後,UI線程就可以自由地更新顯示內容(或者在那裏,它可能不得不在其間做一些其他的小事) – musefan

+0

@musefan,據我瞭解,事件在mainBw中處理線程,而不是在UI線程中。如果我做這樣的事情 tbox.Text =「child」; 在ProgressChanged事件中,它會拋出異常。 – AlexP11223

+0

真的嗎? tbox.Text =「小孩」;在ProgressChanged事件中引發異常? – Paparazzi

回答

2

BackgroundWorker使用通用方式獲取代碼以在UI線程上運行,它使用靜態SynchronizationContext.Current屬性來查找同步提供程序。 ReportProgress()使用其Post()方法來封送通話。

如果您運行Winforms應用程序,則當前屬性將引用WindowsFormsSynchronizationContext class的實例。在創建表單或調用Application.Run()時自動安裝。它使用Control.Begin/Invoke()來實現Post和Send方法。

如果您運行WPF應用程序,那麼當前屬性將引用DispatcherSynchronizationContext的實例,它使用Dispatcher.Begin/Invoke()。

所以這只是自動工作。

+0

他從來沒有使用過這個功能。實際上只有一個捕獲的同步上下文的BGW只處理do work事件。 – Servy

+0

是的,正如本文http://msdn.microsoft.com/en-us/magazine/gg598924.aspx中所述,它使用了默認的ThreadPool SynchonizationContext。 – AlexP11223

1

它的工作原理,因爲BackgroundWorker確實在後臺線程(因此而得名)的工作。由於它不在UI線程中運行,因此它不會阻塞UI線程,它只是每隔一段時間發送簡短的方法在UI線程中運行。

這就是說,它仍然不是一個解決問題的設計得非常好的方法。如果您想每3秒運行一次代碼,只需使用Timer。如果您在Forms命名空間中使用計時器,它將代表您在UI線程中觸發它的事件。

+0

看到我上面的評論,因爲我知道它被編組到mainBw線程,而不是UI線程(因爲它是在mainBw線程中創建的)。 和定時器不是我想要的,這段代碼僅用於演示/測試目的。其實我想在我的mainBw後臺線程中創建一些線程,並且他們應該向mainBw線程報告進度。 – AlexP11223

+0

@ Alex11223正如Hans在他的回答中所說的那樣,BGW查看當前的同步上下文並使用它來將非工作者事件處理程序編組到該上下文中。你的第一個BGW **沒有上下文**,所以BGW的子事件都將在線程池線程中觸發。它們不會在第一個BGW的線程中觸發,因爲它不會創建一個允許這種情況發生的「SynchronizationContext」。 – Servy

0

它有效,因爲BackgroundWorker正如其名稱所示 - 在獨立於主UI線程的後臺線程中運行。

ReportProgress -event被編組到UI線程,以便可以輕鬆地處理此事件,而無需調用Invoke - 涉及的控件的方法。

Contraray的Application.DoEvents() - 方法中的WinForms允許的進程來處理其他消息perfoming長期使用後臺線程在主線程去操作,沒有

+0

看到我上面的評論,因爲我明白它被編組到mainBw線程,而不是UI線程(因爲它是在mainBw線程中創建的)。 – AlexP11223

相關問題