我制作了一个全天候运行的应用,其中三个Backgroundworkers
以不同的时间间隔运行。
在DoWork
我做了一些Dispatcher.BeginInvoke
,所以它更新了一些图表。问题是它在夜间崩溃,我不确定为什么。我已将Dispatcher.BeginInvoke
包装在try / catch中,但由于我正在调用UI线程,我想我可能会尝试使用try {em> INSIDE 来代替Dispatcher.BeginInvoke
重要吗?
答案 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.DispatcherUnhandledException
,AppDomain.CurrentDomain.UnhandledException
事件和DispatcherOperation.Task.Exception
财产,见下文)。如果他们没有处理,他们将在UI线程的核心Dispatcher
事件循环中崩溃应用程序。
这也包括RunWorkerCompletedEventArgs.Error
。在Dispatcher.BeginInvoke
事件后,Error
代理中引发的异常 RunWorkerCompletedEvent
。
这是一个简单示例,说明问题。请注意e.Error
中null
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}}列表无休止地增长。