【发布时间】:2014-02-09 11:44:37
【问题描述】:
我正在查看我同事的一些 WPF 代码,它是基于UserControl 的组件的库,其中包含许多async void 事件和命令处理程序.这些方法目前内部没有实现任何错误处理。
简而言之代码:
<Window.CommandBindings>
<CommandBinding
Command="ApplicationCommands.New"
Executed="NewCommand_Executed"/>
</Window.CommandBindings>
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// do some fake async work (and may throw if timeout < -1)
var timeout = new Random(Environment.TickCount).Next(-100, 100);
await Task.Delay(timeout);
}
在NewCommand_Executed 内部未观察到抛出的异常只能在全局级别上处理(例如,使用AppDomain.CurrentDomain.UnhandledException)。显然,这不是一个好主意。
我可以在本地处理异常:
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{
// do some fake async work (throws if timeout < -1)
var timeout = new Random(Environment.TickCount).Next(-100, 100);
await Task.Delay(timeout);
}
catch (Exception ex)
{
// somehow log and report the error
MessageBox.Show(ex.Message);
}
}
但是,在这种情况下,宿主应用的 ViewModel 不会发现 NewCommand_Executed 中的错误。也不是理想的解决方案,而且错误报告 UI 不应始终是库代码的一部分。
另一种方法是在本地处理它们并触发专门的错误事件:
public class AsyncErrorEventArgs: EventArgs
{
public object Sender { get; internal set; }
public ExecutedRoutedEventArgs Args { get; internal set; }
public ExceptionDispatchInfo ExceptionInfo { get; internal set; }
}
public delegate void AsyncErrorEventHandler(object sender, AsyncErrorEventArgs e);
public event AsyncErrorEventHandler AsyncErrorEvent;
private async void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
ExceptionDispatchInfo exceptionInfo = null;
try
{
// do some fake async work (throws if timeout < -1)
var timeout = new Random(Environment.TickCount).Next(-100, 100);
await Task.Delay(timeout);
}
catch (Exception ex)
{
// capture the error
exceptionInfo = ExceptionDispatchInfo.Capture(ex);
}
if (exceptionInfo != null && this.AsyncErrorEvent != null)
this.AsyncErrorEvent(sender, new AsyncErrorEventArgs {
Sender = this, Args = e, ExceptionInfo = exceptionInfo });
}
我最喜欢最后一个,但如果有任何其他建议,我将不胜感激,因为我在 WPF 方面的经验有些有限。
是否有已建立的 WPF 模式将错误从
async void命令处理程序传播到 ViewModal?在 WPF 命令处理程序中执行异步工作通常是个坏主意,因为它们可能用于快速同步 UI 更新?
我是在 WPF 的上下文中提出这个问题的,但我认为它也适用于 WinForms 中的async void 事件处理程序。
【问题讨论】:
-
This MSDN thread 可能会对您的问题有所了解
-
@ElliotTereschuk,谢谢,该线程引用了another good post。然而,
AwaitableDelegateCommand.Execute从那里仍然没有传播任何内部异常,AFAICT。所以我不确定我们是否可以将它与 XAML 声明性命令绑定一起使用。 -
@Noseratio,你为什么不在 catch 中触发事件表单?为什么会有额外的变量?为什么要向通知发送
ExceptionDispatchInfo而不是异常? -
@PauloMorgado,这是一个
UserControl库,它对 ViewModal 或其外部的任何其他客户端代码一无所知。通过触发这样的错误事件,我让这样的代码有机会以任何所需的方式处理/报告/记录错误。客户端代码的开发人员可以选择通过AsyncErrorEventArgs.ExceptionInfo.SourceException检查异常或通过AsyncErrorEventArgs.ExceptionInfo.Throw()重新抛出异常,或者两者都做。 如果您有其他解决方案,请随时发布答案,这就是问题所要求的。
标签: c# .net wpf error-handling async-await