我对线程的想法还很陌生,我正在使用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