2015-10-13 37 views
0

我有我的類中有一些內部循環的方法。 這個方法的主要目的是轉換一些文件,所以我在我的表單中放置了一個進度條,在每個文件轉換後應該更新。C#BackgroundWorker ProgressChanged不會被觸發,直到函數結束

我嘗試了所有可能的組合,並且閱讀了所有可能的內容,但無法解決此問題。

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    converterProgressBar.Value = e.ProgressPercentage; 
} 

僅在我的方法的主循環執行後才被調用。

這是我的方法:

public string Convert() 
{ 
    convertBtn.Enabled = false; 
    bw.WorkerReportsProgress = true; 
    bw.WorkerSupportsCancellation = true; 

    bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 
    totalCount = files.length; 
    bw.RunWorkerAsync(); 

    if (!Directory.Exists(folder)) 
    { 
     Directory.CreateDirectory(folder); 
    } 
    foreach (string file in files) 
    { 
     countFile++; 
     if (chk.Checked) 
     { 
      class1.DoJob(); 
     } 

     using (// some code)) 
     { 
      using (//some other code)) 
      { 
       try 
       { 
        using (// again some code) 
        { 
         // job executing 
        } 
       } 
       catch (exception 
       { 

       } 
      } 
     } 
     convertedVideosL.Text = txtToUpdate; 
     convertedVideosL.Refresh(); 
    } 
    countFile = countFile + 1; 
    MessageBox.Show("Done"); 
    countFile = -1; 
    return outputFile; 
} 

這裏是BackgroundWorker事件處理程序:

void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    for (int i = 0; i <= totalCount; i++) 
    { 
     if (bw.CancellationPending) 
     { 
      e.Cancel = true; 
     } 
     else 
     { 
      int progress = Convert.ToInt32(i * 100/totalCount); 
      (sender as BackgroundWorker).ReportProgress(progress, i); 
     } 
    } 
} 

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    converterProgressBar.Value = e.ProgressPercentage; 
} 

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Cancelled == false) 
    { 
     convertedVideosL.Text = "Finished!"; 
    } 
    else 
    { 
     convertedVideosL.Text = "Operation has been cancelled!"; 
    } 
} 

但我無法得到更新每一個轉換文件中的進度條。 它等待foreach循環結束,然後調用bw_ProgressChanged

如果我把RunWorkerAsync()放在foreach循環中,會引發一個異常,說明BackgroundWorker忙,不能執行其他任務。

在我看來,很明顯,DoWork()只執行一個for循環,然後它不應該是知道的轉換正在進行,但ProgressChanged應該由ReportProgress(progress,i)被解僱的。

可以請某人解釋我的原因並幫助我解決問題嗎?

謝謝!

+1

根據您發佈的代碼,我認爲您對BackgroundWorker存在誤解。該工作應該發生在BackgroundWorker內部(即將邏輯從Convert轉換爲bw_DoWork)。在循環的每次迭代(在DoWork!內部)觸發ReportProgress方法。 – syazdani

+0

你能否詳細說明一下?因爲我試圖運行DoWork中的代碼,但是如何在循環之後觸發ReportProgress方法?我在哪裏放RunWorkerAsync? –

+1

有很多事情,你需要改變,以使其工作。您應該在bw_DoWork中運行Convert方法,但不應該訪問內部控件(如chk,convertedVideosL),也不應該使用MessageBox-es。你應該從那裏調用bw.ReportProgress並在bw_ProgressChanged中處理它,你可以在這裏更新你的UI。坦率地說,使用'async/await'完成所有這些工作會容易得多,你有這個選擇嗎? –

回答

1

當前轉換不是由BackgroundWorker類型的實例執行的。該轉換應該從DoWork事件處理程序中調用。

請考慮提取轉換相關的功能:

if (!Directory.Exists(folder)) 
{ 
    Directory.CreateDirectory(folder); 
} 
foreach (string file in files) 
{ 
    // Details... 
} 

到單獨的方法。之後,只需調用DoWork事件處理程序的方法即可。

僞代碼來說明這個想法:

public void StartConversion() 
{ 
    ... 
    TWorkerArgument workerArgument = ...; 
    worker.RunWorkerAsync(workerArgument); 
    // No message box here because of asynchronous execution (please see below). 
} 

private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e) 
{ 
    // Get the BackgroundWorker that raised this event. 
    BackgroundWorker worker = sender as BackgroundWorker; 
    e.Result = Convert(worker, (TWorkerArgument)e.Argument); 
} 

private static TWorkerResult Convert(BackgroundWorker worker, TWorkerArgument workerArgument) 
{ 
    if (!Directory.Exists(folder)) 
    { 
     Directory.CreateDirectory(folder); 
    } 

    foreach (string file in files) 
    { 
     // Details... 
     worker.ReportProgress(percentComplete); 
    } 

    return ...; 
} 

private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    // Show the message box here if required. 
} 

請適當更換TWorkerArgumentTWorkerResult類型。

此外,請參閱使用BackgroundWorker類的示例以獲取更多詳細信息:How to: Implement a Form That Uses a Background Operation, MSDN

+0

現在它變得令人困惑:)這是我第一次嘗試實現背景工作,因爲我想學習這個功能,但是我不能跟着你的代碼(當然我的錯誤),TWorkerResult和TWorkerArgument.Could你可以讓它成爲一個比較簡單? –

+1

@Daniel,'TWorkerArgument'是你想要發送給'BackgroundWorker'的數據類型,'TWorkerResult'是你想要返回的數據類型。謝爾蓋不能告訴你他們應該是什麼,因爲你沒有告訴我們你的數據是什麼,也沒有告訴我們你的數據。 –

+0

@DourHighArch,對!究竟! –