加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 06:36:07 所属栏目:百科 来源:网络整理
导读:我正在审查我的同事的一些 WPF代码,这是一个基于UserControl的组件库,带有大量异步无效事件和命令处理程序.这些方法目前在内部不执行任何错误处理. 代码简而言之: Window.CommandBindings CommandBinding Command="ApplicationCommands.New" Executed="NewC
我正在审查我的同事的一些 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需要被通知的“异常”,我建议捕获已知的异常并提出事件/命令并设置属性.但是再次,这真的不应该用于异常,只是预期的“错误”状态.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读