2012-09-27 150 views
0

我有一些在我的WinForms應用程序中運行的重任務。問題是,它在運行時會凍結UI(UI主線程)。在C中異步運行任務#

我還沒有在C#中的線程和委託中工作太多,這就是爲什麼我希望有人可以幫助我,如何處理這些流程繁重的任務,而不凍結用戶界面,所以用戶不認爲該應用在等待時崩潰了?

例如,我已經通過我的FrontController一個電話,這需要時間:

_controller.testExportExcel(wrapper, saveDialog.FileName); 

,因爲它是創建一個Excel文件。我不會在應用程序工作時在UI上做出響應。

的過程,任務重的另一個例子是這樣的:

private void dataGridView_liste_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) 
{ 
    if (e.ListChangedType != ListChangedType.ItemDeleted) 
    { 
    foreach (DataGridViewRow r in dataGridView_liste.Rows) 
    { 
     DataGridViewCellStyle red = dataGridView_liste.DefaultCellStyle.Clone(); 
     red.BackColor = Color.LightGreen; 
     if (r.Cells["News"].Value != null && (bool)r.Cells["News"].Value == true) 
     r.DefaultCellStyle = red; 
    } 
    } 
} 

foreach循環需要一定的時間,並凍結UI。一個異步線程運行進程並在完成時自動關閉,這可能對我有用。但它是如何工作的?

+0

對於'BackgroundWorker'的excel創建外觀。對於第二個循環,所有的代碼都是一個UI代碼,所以它不能被線程化,但它看起來不像一個長時間運行的代碼。你有多少行?你也可以暫停網格繪畫,它可能會有所幫助。 –

+0

您確定這不是重複的嗎? SO有很多類似的問題... –

+0

@AmiramKorach下週將嘗試BackgroundWorker進行方法調用,看看它是否可以幫助我。第二個循環有大約512多行,並且整個想法是爲了視覺上的原因在每行中創建背景綠色。 難道根本就不可能在UI中創建異步運行,所以加載內容時UI不會凍結?和/或使負載微調,顯示用戶界面正在加載???? – grmihel

回答

2

我回答了一個非常類似的問題here

它歸結爲使用的BackgroundWorker。

msdn提供了一個例子:即在DoWork的事件處理程序運行

using System.ComponentModel; 
using System.Windows; 
using System.Windows.Controls; 

namespace SL_BackgroundWorker_CS 
{ 
    public partial class Page : UserControl 
    { 
     private BackgroundWorker bw = new BackgroundWorker(); 

     public Page() 
     { 
      InitializeComponent(); 

      bw.WorkerReportsProgress = true; 
      bw.WorkerSupportsCancellation = true; 
      bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
      bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
      bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
     } 
     private void buttonStart_Click(object sender, RoutedEventArgs e) 
     { 
      if (bw.IsBusy != true) 
      { 
       bw.RunWorkerAsync(); 
      } 
     } 
     private void buttonCancel_Click(object sender, RoutedEventArgs e) 
     { 
      if (bw.WorkerSupportsCancellation == true) 
      { 
       bw.CancelAsync(); 
      } 
     } 
     private void bw_DoWork(object sender, DoWorkEventArgs e) 
     { 
      BackgroundWorker worker = sender as BackgroundWorker; 

      for (int i = 1; (i <= 10); i++) 
      { 
       if ((worker.CancellationPending == true)) 
       { 
        e.Cancel = true; 
        break; 
       } 
       else 
       { 
        // Perform a time consuming operation and report progress. 
        System.Threading.Thread.Sleep(500); 
        worker.ReportProgress((i * 10)); 
       } 
      } 
     } 
     private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if ((e.Cancelled == true)) 
      { 
       this.tbProgress.Text = "Canceled!"; 
      } 

      else if (!(e.Error == null)) 
      { 
       this.tbProgress.Text = ("Error: " + e.Error.Message); 
      } 

      else 
      { 
       this.tbProgress.Text = "Done!"; 
      } 
     } 
     private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      this.tbProgress.Text = (e.ProgressPercentage.ToString() + "%"); 
     } 
    } 
} 

一切都是異步的。
在ProgessChanged/RunWorkCompleted的事件處理程序中運行的所有東西都在UI線程上。

3

如何使用Task(如果定位.net 4)?這被認爲是BackgroundWorker類的替代品,因爲它支持嵌套(父/子任務),任務延續等。

例如,

private void dataGridView_liste_DataBindingComplete(object sender, 
     DataGridViewBindingCompleteEventArgs e) 
    { 
     Task t = Task.Factory.StartNew(() => 
     { 
      // do your processing here - remember to call Invoke or BeginInvoke if 
      // calling a UI object. 
     }); 
     t.ContinueWith((Success) => 
     { 
      // callback when task is complete. 
     }, TaskContinuationOptions.NotOnFaulted); 
     t.ContinueWith((Fail) => 
     { 
      //log the exception i.e.: Fail.Exception.InnerException); 
     }, TaskContinuationOptions.OnlyOnFaulted); 

    } 
0

爲了您的第一個例子,到_controller.testExportExcel()呼叫,BackgroundWorkerTask Parallel Library呼叫(即Task.Factory.StartNew(...))將是適當的satify你保持UI響應的要求。大量的例子浮出水面,包括這裏的其他答案。

對於你的第二個例子,你會發現你不能把它放在後臺線程上,因爲它似乎是操縱UI的代碼。具體來說,如果執行BackgroundWorkerDoWork事件處理函數,或者您傳遞給Task.Factory.StartNew()的委託或普通舊線程的方法觸及UI,那麼極有可能(/某些?)得到一個異常,指出「Cross線程操作無效「。

原因涵蓋在in this question。但是,我更驚訝其實這是足夠慢,你想使它異步。可能有一些簡單的方法可以讓這段代碼更具響應性 - 想起Control.SuspendLayout().ResumeLayout()