捕获线程中的所有异常

时间:2014-03-11 14:52:48

标签: c# wpf multithreading

假设我有控制台应用程序,并希望在另一个线程中运行WPF Window。到目前为止,这是我的解决方案:

var th = new Thread(() =>
{
    try
    {
        System.Windows.Application currentApp = new System.Windows.Application();
        instance = new App.MainWindow(); //instance is declared somewhere else

        currentApp.Run(instance);
    }
    catch (Exception ex)
    {
        //log exception
    }
});
th.SetApartmentState(ApartmentState.STA);
th.Start();

代码中的其他地方我正在更改一些MainWindow属性,如下所示:

instance.Dispatcher.Invoke(() =>
{
    instance.SomeProperty = "Some value";
});

除了例外情况外,一切都运作良好。我认为所有异常都会抛出th线程,并且线程内的try-catch会捕获它们,但事实并非如此。如果SomeProperty抛出异常,它会离开th个线程(或从未进入过它?)并直接出现在我的主线程中,导致我的应用程序崩溃/退出。

我做错了什么? instance.SomeProperty = "Some value";线程上是否th没有执行?如何在th线程上执行它?

2 个答案:

答案 0 :(得分:1)

WPF提供了一些事件,可以帮助您解决问题。首先,有Application.DispatcherUnhandledException Event

private void App_DispatcherUnhandledException(object sender, 
    DispatcherUnhandledExceptionEventArgs e)
{
    // An unhandled Exception occurred!

    // Prevent default unhandled exception processing
    e.Handled = true;
}

从链接页面:

  

应用程序为每个在主UI线程上运行的代码未处理的异常引发DispatcherUnhandledException。

     

如果在后台用户界面(UI)线程(具有自己的Dispatcher的线程)或后台工作线程(没有Dispatcher的线程)上未处理异常,则不会将异常转发到主UI线程。因此,不会引发DispatcherUnhandledException。在这些情况下,您需要编写代码来执行以下操作:

     

1.处理后台线程中的异常。

     

2.将这些异常发送到主UI线程。

     

3.在主UI线程上重新抛出它们而不处理它们以允许引发DispatcherUnhandledException。

您的另一个选择是AppDomain.UnhandledException Event

private void UnhandledExceptions(object sender, UnhandledExceptionEventArgs e)
{
    // An unhandled Exception occurred!
    if (e.IsTerminating)
    {
        // The RunTime is terminating now, so log some error details
    }
}

请注意,此处理程序只是提供了一种方法,可以在收到Exception时记录错误...之后程序关闭,所以这个可能不太有用为了你。从MSDN上的链接页面:

  

此事件提供未捕获异常的通知。它允许应用程序在系统默认处理程序向用户报告异常并终止应用程序之前记录有关异常的信息。如果有足够的有关应用程序状态的信息,则可以采取其他措施 - 例如保存程序数据以便以后恢复。建议小心,因为在未处理异常时程序数据可能会损坏。

关于我提供链接的两个页面上的未处理Exception,还有很多内容需要阅读......你可能会比彻底阅读它们更糟糕。

答案 1 :(得分:-1)

尝试使用 ContinueWith ,最后使用 TaskScheduler.FromCurrentSynchronizationContext()方法。所以你断言要回到mainThread

Debug.WriteLine("command execute on {0}", Thread.CurrentThread.ManagedThreadId);

Task.Factory.StartNew(() =>
{
   Debug.WriteLine("executing on {0}", Thread.CurrentThread.ManagedThreadId);
   Thread.Sleep(1000);
})
  .ContinueWith(t =>
{
  Debug.WriteLine("task finished on {0}", Thread.CurrentThread.ManagedThreadId);
}, TaskScheduler.FromCurrentSynchronizationContext());

希望有所帮助。问候!