异常处理内部和QUOT;异步无效" WPF命令处理程序 [英] Exception handling inside "async void" WPF command handlers

查看:189
本文介绍了异常处理内部和QUOT;异步无效" WPF命令处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我回顾我的同事一些WPF code,这是用户控件基于组件的挺多的 异步无效 事件和​​命令处理程序。这些方法目前不实现任何错误处理内部。

I'm reviewing some WPF code of my colleagues, which is a library of UserControl-based components with a lot of async void event and command handlers. These methods currently do not implement any error handling internally.

在code一言以蔽之:

The code in a nutshell:

<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 )。显然,这不是一个好主意。

Exceptions thrown but not observed inside NewCommand_Executed can only be handled on a global level (e.g., with AppDomain.CurrentDomain.UnhandledException). Apparently, this is not a good idea.

我可以在本地处理异常:

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);
    }
}

然而,在这种情况下,主机应用程序的视图模型是不知道的错误 NewCommand_Executed 的。不是一个理想的解决方案,再加上错误报告的用户界面,总是应该的库code的一部分。

However, in this case the host app's ViewModel would be unaware of errors inside NewCommand_Executed. Not an ideal solution either, plus the error reporting UI shouldn't always be a part of the library code.

另一种方法是在本地处理他们和消防专用的错误事件:

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 });
}

我喜欢最后一个之最,但我想AP preciate任何其他建议,我的经验与WPF是比较有限的。

I like the last one the most, but I'd appreciate any other suggestions as my experience with WPF is somewhat limited.

  • 是否有一个既定的WPF模式传播从错误异步无效命令处理程序ViewModal?

  • Is there an established WPF pattern to propagate errors from async void command handlers to ViewModal?

是它通常是一个坏主意,做内部WPF命令处理程序异步工作,也许他们正在用于快速同步UI更新?

Is it generally a bad idea to do async work inside WPF command handlers, as perhaps they're intended for quick synchronous UI updates?

我问在WPF的背景下,这个问题,但我认为它可能也适用于异步无效事件处理程序中的WinForms。

I'm asking this question in the context of WPF, but I think it may as well apply to async void event handlers in WinForms.

推荐答案

这里的问题是,你的用户控件库不是在一个典型的MVVM方式架构。通常情况下,对于非普通的命令,你的用户控件的code不会绑定到命令直接,而是将有属性,当设置(通过绑定到一个视图模型)将触发控制动作。那么你的视图模型将绑定到应用程序的命令,并设置相应的属性。 (或者,您的MVVM框架可能有另一个消息传递的情况下,可以利用该视图模型和视图之间的交互)。

The issue here is that your UserControl library is not architected in a Typical MVVM way. Commonly, for non-trivial commands, your UserControl's code would not bind to commands directly, but instead would have properties that when set (through binding to a ViewModel) would trigger the action in the control. Then your ViewModel would bind to the application command, and set the appropriate properties. (Alternatively, your MVVM framework may have another message passing scenario that can be leveraged for interaction between the ViewModel and View).

对于那些在UI内抛出的异常,我又觉得有一个结构问题。如果用户控件是做多作为一个视图,(即运行任何可能导致意想不到的异常业务逻辑),那么这应该分成视图和视图模型。该视图模型将运行逻辑既可以通过你的其它应用的ViewModels被实例化,或通过其他方法进行通信(如上所述)。

As for Exceptions that are thrown inside the UI, I again feel that there is an architecture issue. If the UserControl is doing more than acting as a View, (i.e. running any kind of business logic that might cause unanticipated exceptions) then this should be separated into a View and a ViewModel. The ViewModel would run the logic and could either be instantiated by your other application ViewModels, or communicate via another method (as mentioned above).

如果有被扔在用户控件的布局/可视化code,那么这应该(几乎毫无例外)不会被抓以任何方式通过你的ViewModel例外。这应该,正如你所说,只用于记录由一个全球级别的处理程序进行处理。

If there are exceptions being thrown by the UserControl's layout / visualization code then this should (almost without exception) not be caught in any way by your ViewModel. This should, as you mentioned, only be handled for logging by a global level handler.

最后,如果没有真正的被称为异常在控制的code,您的视图模型需要通知一下,我建议抓住已知的异常和引发事件/命令,并设置一个属性。但同样,这实在不应该被用于例外,只是预期的错误状态。

Lastly, if there truly are known 'exceptions' in the Control's code that your ViewModel needs to be notified about, I suggest catching the known exceptions and raising an event/command and setting a property. But again, this really shouldn't be used for exceptions, just anticipated 'error' states.

这篇关于异常处理内部和QUOT;异步无效&QUOT; WPF命令处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆