代码之家  ›  专栏  ›  技术社区  ›  jpbochi

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

  •  14
  • jpbochi  · 技术社区  · 16 年前

    这是我假设的例子。我有一个非常简单的WPF窗口和一个按钮。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);
    

    我希望这个例外会被 Trace.WriteLine 打电话。相反,不会捕获异常,应用程序会中断。

    有人知道可能的解释吗?为了捕获由调用的委托引发的异常,您建议什么解决方法 Dispatcher.Invoke ?

    更新1 我放了一个 throw 在异常处理代码中。我不想忽略这个例外。我问题的关键是要正确处理。问题是从未执行异常处理代码。

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

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

    this.Invoke(error);
    

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

    1 回复  |  直到 11 年前
        1
  •  6
  •   Stephen Cleary    16 年前

    更新: 要观察另一个线程中的异常,您需要使用 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); 
    

    更新(再次): 因为您的目标是一个可重用的组件,所以我建议您转到 任务 -基于接口或其他基于 SynchronizationContext event-based asynchronous pattern ,而不是基于 调度员 ISynchronizeInvoke .

    调度员 -基于组件仅在WPF/Silverlight上工作; 同步调用 -基于组件仅在Windows窗体上工作。 行绪 -基于组件将透明地与WPF或Windows窗体以及(稍微多一些工作)ASP.NET、控制台应用程序、Windows服务等一起工作。

    基于事件的异步模式是旧的推荐写入方式 行绪 -基于组件;它仍然适用于.NET 3.5时代的代码。但是,如果您使用的是.NET 4,那么任务并行库就更加灵活、干净和强大了。这个 任务计划程序.fromCurrentSynchronizationContext 使用 行绪 下面是编写需要这种同步的可重用组件的新方法。