我對線程的想法還很陌生,我正在使用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()
中包裝兩種方法嗎?雖然,我真的覺得我不應該在同一個函數中使用其中的兩個調用。有沒有更好的方法去做我想做的事情?
從另一個線程修改控件的唯一方法是使用Dispatcher.Invoke()。 – 2013-04-05 15:33:56
您不能在工作線程中訪問cmbDateSelecter等控件的屬性。用worker中需要的值創建一個輔助類,並將其傳遞給RunWorkerAsync(object)過載。將它從您的DoWork事件處理函數中的e.Argument轉換回來。 – 2013-04-05 15:55:07
而不是直接管理您的線程考慮使用基於任務的異步模式(TAP)。這裏有一個關於使用TAP的進度報告的簡短教程:http://simplygenius.net/Article/AncillaryAsyncProgress – 2013-04-05 16:33:36