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()吗?不过,老实说,我不应该在同一个函数中使用其中两个调用。有没有更好的方法来完成我正在尝试做的事情?

4

1 回答 1

3

您可以通过后台工作人员的 ProgressChanged 事件传回数据。这将封送回 UI 线程。该文档让您知道您通过调用ReportProgress来调用此事件

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

如果您想要某种方法来分部分执行它,那么这Invoke是唯一的另一种方法。

于 2013-04-05T15:30:27.203 回答