2013-04-05 82 views
1

我對線程的想法還很陌生,我正在使用BackgroundWorker,試圖在進行一些工作時顯示進度條。這裏的DoWork事件的BackgroundWorker由不同線程擁有的對象

private void BackgroundWorker1DoWork(object sender, DoWorkEventArgs e) 
{ 
    SetDateStartEndTimeForReport(); 

    try 
    { 
      PopulateGrid(); 

    } 
    catch (Exception ex) 
    { 
      Logger.Error(ex.Message); 
      MessageBox.Show(ex.Message); 
      return; 
    } 
} 

現在,我的SetDateStartEndTimeForReport()裏,我得到一個InvalidOperationException

private void SetDateStartEndTimeForReport() 
{ 
    Logger.Info("Setting the chosen date and/or start/end times for report..."); 

    // Quite possibly the best yo-yo code I've ever written 
    // "Look, I'm a string. Nope, I'm a DateTime. Tricked you again, I'm a string." 
    var reportDate = Convert.ToDateTime(cmbDateSelecter.SelectedValue.ToString()).ToString("yyyy-MM-dd"); // Exception occurs here 

    Report.Date = reportDate; 

    if (chkboxTimeFrame.IsChecked == true) 
    { 
     Report.StartTime = timeStart.Value.Value.ToString(reportDate + " HH:mm"); 
     Report.EndTime = timeEnd.Value.Value.ToString(reportDate + " HH:mm"); 
    } 

    Logger.Info("Date and/or start/end times set"); 
} 

的異常狀態:

調用線程不能訪問該對象因爲不同的線程擁有它。

所以,我做了一些研究,並找到了約this.Dispatcher.Invoke((Action)(()。現在,當我換,該SetDateStartEndTimeForReport();

this.Dispatcher.Invoke((Action)(() => 
{ 
    SetDateStartEndTimeForReport(); 
})); 

PopulateGrid()拋出同樣的異常。現在,我可以將該方法包裝在相同的Dispatcher.Invoke()中,這就讓問題消失了。不過,我覺得我好像錯過了一些更優雅的東西。在函數調用時,任何UI元素都不應該被其他任何東西使用。我的問題是,我可以在相同的Dispatcher.Invoke()中包裝兩種方法嗎?雖然,我真的覺得我不應該在同一個函數中使用其中的兩個調用。有沒有更好的方法去做我想做的事情?

+0

從另一個線程修改控件的唯一方法是使用Dispatcher.Invoke()。 – 2013-04-05 15:33:56

+0

您不能在工作線程中訪問cmbDateSelecter等控件的屬性。用worker中需要的值創建一個輔助類,並將其傳遞給RunWorkerAsync(object)過載。將它從您的DoWork事件處理函數中的e.Argument轉換回來。 – 2013-04-05 15:55:07

+0

而不是直接管理您的線程考慮使用基於任務的異步模式(TAP)。這裏有一個關於使用TAP的進度報告的簡短教程:http://simplygenius.net/Article/AncillaryAsyncProgress – 2013-04-05 16:33:36

回答

3

您可以通過background worker's ProgressChanged event傳回數據。這將回傳到UI線程。該文檔可讓您知道您通過致電ReportProgress

請注意,BackgroundWorker's只應在其DoWork中執行業務邏輯。如果你所做的只是更新用戶界面,那麼你不能在後臺線程上執行此操作。如果您需要檢索數據,則可以使用後臺工作程序將其加載到內存中,並且在完成後,如果已將其掛接(將在UI線程上),將調用OnRunWorkerCompleted事件

如果您想要某種方法來完成它,然後Invoke是唯一的方法。

+0

聽起來好像'PopulateGrid'屬於已完成事件,而另一部分正在進行中,因此他'你需要利用這兩個事件。 – Servy 2013-04-05 15:31:46

+0

我剛剛添加到我的回答:) – 2013-04-05 15:35:13

相關問題