对象由不同的线程拥有

时间:2013-04-05 15:23:30

标签: c# multithreading thread-safety

我对线程的想法很新,我正在使用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()中包含两个方法吗?虽然,老实说我觉得我不应该在同一个函数中使用其中两个调用。有没有更好的方法来解决我正在尝试做的事情?

1 个答案:

答案 0 :(得分:3)

您可以通过background worker's ProgressChanged event传回数据。这将封送回UI线程。该文档通过调用ReportProgress

告知您调用此事件

请注意,BackgroundWorker's只应在其DoWork中执行业务逻辑。如果您所做的只是更新UI,那么您无法在后台线程上执行此操作。如果你需要检索数据,那么你可以使用后台工作程序将其加载到内存中,完成后,如果你连接它(它将在UI线程上),它将调用OnRunWorkerCompleted事件

如果你想要某种方法来部分地做到这一点,那么Invoke是唯一的另一种方式。