c# – “async void”中的异常处理WPF命令处理程序

前端之家收集整理的这篇文章主要介绍了c# – “async void”中的异常处理WPF命令处理程序前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在审查我的同事的一些 WPF代码,这是一个基于UserControl的组件库,带有大量异步无效事件和命令处理程序.这些方法目前在内部不执行任何错误处理.

代码简而言之:

<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模式,以将错误从异步无效命令处理程序传播到ViewModal?
>在WPF命令处理程序中执行异步工作通常是一个坏主意,也许它们用于快速同步UI更新?

我在WPF的上下文中提出这个问题,但是我认为它也可以应用于WinForms中的async void事件处理程序.

解决方法

这里的问题是您的UserControl库没有以典型的MVVM方式架构.通常,对于不平凡的命令,您的UserControl的代码将不会直接绑定到命令,而是具有设置(通过绑定到viewmodel)将触发控件中的操作的属性.然后,您的viewmodel将绑定到应用程序命令,并设置相应的属性. (或者,您的MVVM框架可能会有另一个消息传递场景,可以用于viewmodel和View之间的交互).

对于UI中抛出的异常,我再次觉得有一个架构问题.如果UserControl做的不只是作为View,(即运行任何可能导致意外的异常的业务逻辑),那么这应该分为View和viewmodel. viewmodel将运行逻辑,可以由您的其他应用程序viewmodels实例化,也可以通过另一种方法进行通信(如上所述).

如果UserControl的布局/可视化代码抛出异常,那么这个应用程序(几乎无一例外)不会以任何方式被viewmodel所捕获.正如您所提到的,这应该仅由全局级处理程序处理以进行日志记录.

最后,如果在控件的代码中真正知道您的viewmodel需要被通知的“异常”,我建议捕获已知的异常并提出事件/命令并设置属性.但是再次,这真的不应该用于异常,只是预期的“错误”状态.

原文链接:https://www.f2er.com/csharp/95146.html

猜你在找的C#相关文章