我对线程的想法很新,我正在使用BackgroundWorker
,尝试在完成某些工作时显示进度条。以下是DoWork
的{{1}}事件:
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()
中,这会使问题消失。但是,我觉得好像我错过了一些更优雅的东西。在函数调用时,UI元素都不应该被其他任何东西使用。我的问题是,我可以在同一个Dispatcher.Invoke()
中包含两个方法吗?虽然,老实说我觉得我不应该在同一个函数中使用其中两个调用。有没有更好的方法来解决我正在尝试做的事情?
答案 0 :(得分:3)
您可以通过background worker's ProgressChanged event传回数据。这将封送回UI线程。该文档通过调用ReportProgress
告知您调用此事件请注意,BackgroundWorker's
只应在其DoWork
中执行业务逻辑。如果您所做的只是更新UI,那么您无法在后台线程上执行此操作。如果你需要检索数据,那么你可以使用后台工作程序将其加载到内存中,完成后,如果你连接它(它将在UI线程上),它将调用OnRunWorkerCompleted事件
如果你想要某种方法来部分地做到这一点,那么Invoke
是唯一的另一种方式。