为什么WPF Dispatcher.Invoke不传播异常?

jpb*_*chi 14 .net wpf exception-handling exception invoke

这是我的假设例子.我有一个非常简单的WPF窗口,带有一个Button.Button.Click事件有一个像这样的处理程序.

Action doit = () =>
{
    Action error = () => { throw new InvalidOperationException("test"); };

    try {
        this.Dispatcher.Invoke(error, DispatcherPriority.Normal);
    } catch (Exception ex) {
        System.Diagnostics.Trace.WriteLine(ex);
        throw;
    }
};
doit.BeginInvoke(null, null);
Run Code Online (Sandbox Code Playgroud)

我希望通过Trace.WriteLine调用捕获并记下异常.相反,没有捕获异常并且应用程序中断.

有人知道可能的解释吗?为了捕获被调用的委托抛出的异常,您建议使用哪种解决方法Dispatcher.Invoke

更新1:我throw在异常处理代码中添加了一个.我不想实际忽略该异常.我的问题的重点是正确处理它.问题是永远不会执行异常处理代码.

请记住,这是一个假设的例子.我的真实代码看起来不像那样.另外,假设我无法更改要调用的方法中的代码.

更新2:考虑这个类似的例子.我有一个Windows窗体窗口而不是WPF窗口.它有一个按钮,几乎完全相同的处理程序.唯一的区别在于调用代码.它是这样的.

this.Invoke(error);
Run Code Online (Sandbox Code Playgroud)

在Windows窗体中,执行异常处理代码.为什么不同?

Ste*_*ary 6

更新:要观察另一个线程中的异常,您要使用a Task,将其Dispatcher排入线程(使用TaskScheduler.FromCurrentSynchronizationContext),并等待它,如下所示:

var ui = TaskScheduler.FromCurrentSynchronizationContext();
Action doit = () => 
{ 
    var error = Task.Factory.StartNew(
        () => { throw new InvalidOperationException("test"); },
        CancellationToken.None,
        TaskCreationOptions.None,
        ui); 

    try { 
        error.Wait(); 
    } catch (Exception ex) { 
        System.Diagnostics.Trace.WriteLine(ex); 
    } 
}; 
doit.BeginInvoke(null, null); 
Run Code Online (Sandbox Code Playgroud)

(再次)更新:既然你的目标是可重用的组件,我建议迁移到Task基于接口或其他东西依据SynchronizationContext,如基于事件的异步模式,而不是在基础部件DispatcherISynchronizeInvoke.

Dispatcher基于组件的组件仅适用于WPF/Silverlight; ISynchronizeInvoke基于组件的组件仅适用于Windows窗体.SynchronizationContext基于组件的组件可以透明地与WPF或Windows Forms一起使用,并且(有更多工作)ASP.NET,控制台应用程序,Windows服务等.

基于事件的异步模式是编写SynchronizationContext基于组件的旧方法; 它仍然适用于.NET 3.5时代代码.但是,如果您使用的是.NET 4,则任务并行库更加灵活,干净且功能强大.下面的TaskScheduler.FromCurrentSynchronizationContext用法SynchronizationContext,是编写需要这种同步的可重用组件的新方法.

  • 在这种情况下,我实际上建议转移到基于"任务"的接口或基于`SynchronizationContext`的其他东西,例如[基于事件的异步模式](http://msdn.microsoft.com/en-us /library/wewwczdw.aspx).原因是基于"SynchronizationContext"的方法可以透明地使用WPF或Windows Forms,并且(稍微有点工作)ASP.NET,控制台应用程序,Windows服务等等.因此,如果您的目标是可重用的组件,请坚持使用`SynchronizationContext`. (2认同)