尝试调用UI线程

时间:2014-01-21 11:33:38

标签: c# wpf exception thread-safety backgroundworker

我制作了一个全天候运行的应用,其中三个Backgroundworkers以不同的时间间隔运行。

DoWork我做了一些Dispatcher.BeginInvoke,所以它更新了一些图表。问题是它在夜间崩溃,我不确定为什么。我已将Dispatcher.BeginInvoke包装在try / catch中,但由于我正在调用UI线程,我想我可能会尝试使用try {em> INSIDE 来代替Dispatcher.BeginInvoke

重要吗?

2 个答案:

答案 0 :(得分:2)

测试RunWorkerCompleted方法中的EventArgs Error属性是否为null

backgroundWorker.RunWorkerCompleted += (s, e) =>
{
    if (e.Error != null)
    {
        // handle error
    }
}

try/catch仅适用于当前线程中发生的事情。如果在另一个线程中发生错误,则工作人员将完成,但除非您检查Error属性,否则您不知道原因。

答案 1 :(得分:1)

Dispatcher.BeginInvoke排队的回调是异步的。您应该观察您传递到Dispatcher.BeginInvoke 的代理中的所有异常,因为它们不会在其外的任何位置传播(除了Application.Current.DispatcherUnhandledExceptionAppDomain.CurrentDomain.UnhandledException事件和DispatcherOperation.Task.Exception财产,见下文)。如果他们没有处理,他们将在UI线程的核心Dispatcher事件循环中崩溃应用程序。

这也包括RunWorkerCompletedEventArgs.Error。在Dispatcher.BeginInvoke事件后,Error代理中引发的异常 RunWorkerCompletedEvent

这是一个简单示例,说明问题。请注意e.Errornull RunWorkerCompleted的内容// UI Thread // prepare the message window var window = new Window { Content = new TextBlock { Text = "Wait while I'm doing the work..." }, Width = 200, Height = 100 }; // run the worker var dispatcher = Dispatcher.CurrentDispatcher; var worker = new BackgroundWorker(); worker.DoWork += (s, e) => { // do the work Thread.Sleep(1000); // update the UI dispatcher.BeginInvoke(new Action(() => { throw new ApplicationException("Catch me if you can!"); })); // do more work Thread.Sleep(1000); }; worker.RunWorkerCompleted += (s, e) => { // e.Error will be null if (e.Error != null) MessageBox.Show("Error: " + e.Error.Message); // close the message window window.Close(); }; // start the worker worker.RunWorkerAsync(); // show the modal message window // while the worker is working window.ShowDialog();

var step = 0; // progress

// do the work on a background thread
// ..

var lastStep = step++;
Dispatcher.BeginInvoke(new Action(() => 
{
    try 
    {
        // do the UI update
    }
    catch(Exception ex)
    {
        // log or report the error here
        MessageBox.Show("Error during step #" + 
            lastStep + ": " + ex.ToString());
    }
}));

要解决问题,请使用以下内容观察异常:

DispatcherOperation

另外,您可以跟踪Dispatcher.BeginInvoke返回的所有var invokes = new List<DispatcherOperation>(); // do the work on a background thread // .. invokes.Add(Dispatcher.BeginInvoke(new Action(() => { /* update the UI */ }))));

DispatcherOperation.Task.Exception

然后,您可以检查已使用Dispatcher.BeginInvoke排队的每个调用的invokes。我不认为这是可行的,除非你可以阻止{{1}}列表无休止地增长。