C# SynchronizationContext和DispatcherUnhandledException
我遇到了这样一种情况:UI线程中抛出的异常不会在调用线程中被捕获C# SynchronizationContext和DispatcherUnhandledException,c#,dispatcher,synchronizationcontext,C#,Dispatcher,Synchronizationcontext,我遇到了这样一种情况:UI线程中抛出的异常不会在调用线程中被捕获 using System; using System.Diagnostics; using System.Threading; using System.Windows; namespace SynchronisationContextAndExceptionWPF { public partial class MainWindow : Window { private readonly Sync
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
namespace SynchronisationContextAndExceptionWPF
{
public partial class MainWindow : Window
{
private readonly SynchronizationContext _synchronizationContext;
public MainWindow()
{
InitializeComponent();
_synchronizationContext = SynchronizationContext.Current;
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
throw;
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
}
private static void DoSomethingOnUiThreadThatThrowsException()
{
throw new Exception("Any Exception...");
}
}
}
private void button_Click(object sender, RoutedEventArgs e)
{
Exception threadException = null;
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception ex)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
threadException = ex;
//throw; --> don't throw exception here; otherwise you will get DispatcherUnhandledException twice.
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
if(threadException != null)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw threadException; //throw you previously catched exception here.
}
}
首先,我认为这是不可能的(我找到的所有文档都说我可以在那里捕获异常)。
经过一些研究,我发现了问题:我的应用程序使用了一个未处理的ExceptionHandler。处理DispatcherUnhandledException事件的。我向用户显示一些信息并设置e.Handled=true代码>:
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
namespace SynchronisationContextAndExceptionWPF
{
public partial class App : Application
{
public App()
{
DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private static void App_DispatcherUnhandledException(
object sender,
DispatcherUnhandledExceptionEventArgs e)
{
Debug.WriteLine("Catched Exception in UnhandledExceptionHandler.");
// This line makes the difference:
e.Handled = true;
}
}
}
那么问题是:为什么即使我处理了dispatchernhandledexception
-事件,也会引发它?
如何解决这种情况?在lambda表达式中,可以设置一个异常变量,然后在调用线程中检查该变量。若已设置,则在调用线程时抛出异常
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows;
namespace SynchronisationContextAndExceptionWPF
{
public partial class MainWindow : Window
{
private readonly SynchronizationContext _synchronizationContext;
public MainWindow()
{
InitializeComponent();
_synchronizationContext = SynchronizationContext.Current;
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
throw;
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
}
private static void DoSomethingOnUiThreadThatThrowsException()
{
throw new Exception("Any Exception...");
}
}
}
private void button_Click(object sender, RoutedEventArgs e)
{
Exception threadException = null;
try
{
_synchronizationContext.Send(
x =>
{
try
{
DoSomethingOnUiThreadThatThrowsException();
}
catch (Exception ex)
{
Debug.WriteLine("Catched Exception in thread that threw it.");
threadException = ex;
//throw; --> don't throw exception here; otherwise you will get DispatcherUnhandledException twice.
}
}, null);
}
catch (Exception)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw;
}
if(threadException != null)
{
Debug.WriteLine("Catched Exception in thread that calles Send-Method.");
throw threadException; //throw you previously catched exception here.
}
}
亲切问候,,
Daniel如果你有很多控件,你可以生成一个新的类来记住特殊的异常变量。因此,您只需要更改_synchronizationContext的初始化(希望只在控件的基类中更改一次)
当然这会有用。。。但这意味着我必须记住每次都这样称呼它。。。另外:如果我有一个模块化的软件,其中我有这样工作的控件(并且不知道未处理的ExceptionHandler),它们将不会像预期的那样工作……这对我来说很有用!这也许不是所有人的普遍解决办法,但现在让我很高兴。谢谢