async/await Model View Presenter winforms

本文关键字:Presenter winforms View Model await async | 更新日期: 2023-09-27 17:53:41

我有一个winforms应用程序,它使用了这篇文章中描述的MVP模式http://www.codeproject.com/Articles/563809/UIplusDesignplusUsingplusModel-View-Presenter我正在将我的应用程序转换为async/await,但我有问题。

这里有一个例子来说明我的问题

public interface IView
{
    event Action DoSomething;
}
public partial class MyForm : Form, IView
{
    public event Action DoSomething;
    public MyForm() 
    {
        InitializeComponent();
    }
    private async void OnSomeButtonClick(object sender, EventArgs e)
    {
        if (DoSomething!= null)
        {
            try
            {
                await DoSomething();
                SomeOtherMethod();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }   
    }
}
public class MyPresenter
{
    private readonly IView _view;
    private ClassWithAwaitbleMethods _foo;
    public MyPresenter(IView view)
    {
        _view = view;
        _view.DoSomething += OnDoSomething;
        _foo = new ClassWithAwaitableMethods();
    }
    public async void OnDoSomething()
    {
        //this may throw an exception
        await _foo.SomeAwaitableWork1();
    }
}
public class MySecondPresenter
{
    private readonly IView _view;
    private ClassWithAwaitbleMethods _foo;
    public MySecondPresenter(IView view)
    {
        _view = view;
        _view.DoSomething += OnDoSomething;
        _foo = new AnotherClassWithAwaitableMethods();
    }
    public async void OnDoSomething()
    {
        //this may throw an exception
        await _foo.SomeAwaitableWork2();
    }
}

这段代码没有正确地等待,当抛出异常时,它没有被捕获。这是因为async void。当这段代码不是async/await时,异常被很好地捕获。

我知道async void是一个禁忌,除了顶级事件,但我的应用程序的设计方式,我不能真的绕过它。当我只有一个订阅者时,我将IView接口更改为

public interface IView
{
    Func<Task> DoSomething {get; set;};
}

然后像这样连接起来

public MyPresenter(IView view)
{
        _view = view;
        _view.DoSomething = OnDoSomething;
        _foo = new ClassWithAwaitableMethods();
}

虽然有点粗糙,但是可以正确地等待并捕获异常。如有任何帮助或见解,我将不胜感激。

async/await Model View Presenter winforms

核心问题是代码使用事件作为策略模式而不是观察者模式。按照目前的情况,你对这段代码做不了什么;正确的重构需要回调接口而不是事件。例如:

// An instance of this is passed into the concrete view.
public interface IViewImplementation
{
  void DoSomething();
  // Or the async equivalent:
  //   Task DoSomethingAsync();
}

但是,如果这种级别的重构令人讨厌,您可以应用一些变通方法。我在我的博客上报道了这类"异步事件"。有几种方法;定义一个返回Task的事件是可能的(尽管有些尴尬)。不过,我最喜欢的方法是延迟,主要是因为延迟是WinRT开发人员已经熟悉的概念。