我正在审查我的同事们的一些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
事件处理程序。
AwaitableDelegateCommand.Execute
仍然不会传播任何内部异常。因此,我不确定我们是否可以将其与XAML声明式命令绑定一起使用。 - noseratio - open to workcatch
之外执行它。 - noseratio - open to workExceptionDispatchInfo.Throw()
来重新抛出它,并具有相同的调试信息,更多信息请见:https://dev59.com/P2Qn5IYBdhLWcg3wtpBW。 - noseratio - open to workAsyncErrorEventArgs.ExceptionInfo.SourceException
检查异常或通过AsyncErrorEventArgs.ExceptionInfo.Throw()
重新抛出异常或两者都执行。如果您有其他解决方案,请随时发布答案,这就是问题所在。 - noseratio - open to work