2012-10-03 149 views
0

我想在數據網格中顯示臨時文件,因此這是一個長期的過程,我在我的C#.net WPF應用程序中使用後臺工作。後臺工作人員在WPF中無法正常工作

我的代碼是

private System.ComponentModel.BackgroundWorker _background = new System.ComponentModel.BackgroundWorker(); 

    private void button1_Click(object sender, RoutedEventArgs e) 
     { 
      _background.RunWorkerAsync(); 
     } 

    public MainWindow() 
     { 
      InitializeComponent(); 
      this._background.DoWork += new DoWorkEventHandler(_background_DoWork); 
      this._background.RunWorkerCompleted += new  
      RunWorkerCompletedEventHandler(_background_RunWorkerCompleted); 
      this._background.WorkerReportsProgress = true; 
      _background.WorkerSupportsCancellation = true; 

     } 


void _background_DoWork(object sender, DoWorkEventArgs e) 

{ 

this.Dispatcher.Invoke((Action)(() => 
    { 
     try 
     { 
      FileInfo[] files = new 
      DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles(); 

      foreach (FileInfo fi in files) 
      { 
       if (fi != null)    
       {     
        dataGrid1.Items.Add(fi);   

       } 
      }   
     } 
     catch { } 
    })); 
} 

void _background_RunWorkerCompleted(object sen, RunWorkerCompletedEventArgs e) 
     { 

      if (e.Cancelled) 
      { 
      MessageBox.Show("Cancelled"); 
      } 
      else if (e.Error != null) 
      { 
       MessageBox.Show("Exception Thrown"); 
      } 

    } 

所有的代碼運行,但是當數據網格是裝載意味着我的UI做程序運行時沒有響應它掛起。

在上述情況下需要做些什麼修改才能順利運行後臺工作?

除此之外,如果我想添加一個ProgressBar,並與此應用程序一起進步,那我該怎麼辦?

謝謝你

回答

0

使用DirectoryInfo.EnumerateFiles

這條線:

this.Dispatcher.Invoke 

在主線程同步執行的代碼,所以有沒有好處,從使用的BackgroudWorker這樣的方式,因爲DirectoryInfo.GetFiles只有在目錄中的所有文件列舉的回報。

另一方面,DirectoryInfo.EnumerateFiles是懶惰的。你可以寫這樣的事情:

void _background_DoWork(object sender, DoWorkEventArgs e) 
{ 
    var info = new DirectoryInfo(System.IO.Path.GetTempPath()); 

    // now enumeration happens in background 
    foreach (var fi in info.EnumerateFiles()) 
    { 
     // main thread in used only when there is next enumeration result available 
     Dispatcher.Invoke((Action)(() => dataGrid1.Items.Add(fi))); 
    } 
} 
0

嘗試採取這一行動關閉接線員:

FileInfo[] files = new DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles(); 

應該只做涉及UI訪問或修改小而快速的操作。看到這個鏈接:http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

你的繁重工作可以通過BackgroundWorker來完成,並使用Dispatcher來更新dataGrid.Items集合。

嘗試使用調度使用:

Dispatcher.BeginInvoke() 
3

使用this.Dispatcher.Invoke,您實際上編組工作回到UI線程。這沒有任何意義:在執行此操作時,您正在阻止UI線程。

分成兩個部分工作:

  • 慢的部分,這是檢索文件,並應在Dispatcher.Invoke
  • 的UI更新外完成,必須在Dispatcher.Invoke,或進行(更好)在RunWorkerCompleted事件處理程序中。

後臺工作者組件的製作完全如此,以至於您無需使用調度程序手動調度UI工作。例如,你可以存儲在一個領域,你在DoWork方法填補了文件,並用於填充數據網格的RunWorkerCompleted事件:

FileInfo[] files; 

void _background_DoWork(object sender, DoWorkEventArgs e) 
{ 
    files = new DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles(); 
} 

void _background_RunWorkerCompleted(object sen, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Cancelled) 
    { 
     MessageBox.Show("Cancelled"); 
    } 
    else if (e.Error != null) 
    { 
     MessageBox.Show("Exception Thrown"); 
    } 
    else 
    { 
     foreach (FileInfo fi in files) 
     { 
       dataGrid1.Items.Add(fi);   
     } 
    } 
} 

注:如果您使用的是C#5,你現在有一個更簡單的方法,使用async/await功能。所有你需要的是這樣的:

private async void button1_Click(object sender, EventArgs e) 
    { 
     button1.Enabled = false; 
     try 
     { 
      var files = await Task.Run(() => 
       new DirectoryInfo(System.IO.Path.GetTempPath()).GetFiles() 
      ); 
      foreach (var f in files) 
       this.dataGrid1.Items.Add(f.Name); 
     } 
     catch (Exception e) 
     { 
      MessageBox.Show("Exception thrown!"); // do proper error handling here... 
     } 
     finally 
     { 
      button1.Enabled = true; 
     } 
    } 

所有其餘的cruft是由編譯器照顧。

0

您應該更新RunWorkerComplete或ProgressChanged事件處理程序中的UI。

嘗試是這樣的:

public Program() 
    { 
     w = new BackgroundWorker(); 
     w.DoWork += new DoWorkEventHandler(w_DoWork); 
     w.ProgressChanged += new ProgressChangedEventHandler(w_ProgressChanged); 
     w.RunWorkerCompleted += new RunWorkerCompletedEventHandler(w_RunWorkerCompleted); 
     w.WorkerReportsProgress = true; 
     w.WorkerSupportsCancellation = true; 

     w.RunWorkerAsync(); 
    } 

    void w_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     FileInfo[] files = e.Result as FileInfo[]; 
     foreach (FileInfo fi in files) 
     { 
      //dataGrid1.Items.Add(fi); 
     } 
    } 

    void w_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     FileInfo fi = e.UserState as FileInfo; 
     //dataGrid1.Items.Add(fi); 
    } 

    void w_DoWork(object sender, DoWorkEventArgs e) 
    { 
     var w = sender as BackgroundWorker; 

     FileInfo[] files = new DirectoryInfo(
      Path.GetTempPath()).GetFiles(); 

     // Using ProgressChanged 
     foreach (FileInfo fi in files) 
     { 
      w.ReportProgress(0, fi); 
     } 

     // Using RunWorkerCompleted 
     e.Result = files; 
    } 

而且,沒有必要在DoWork的在try/catch語句,異常自動捕獲並報告爲runworkercomplete事件錯誤。