async / await模型视图Presenter winforms

时间:2015-06-06 02:51:57

标签: c# winforms async-await

我有一个使用MVP模式的winforms应用程序,如本文所述 http://www.codeproject.com/Articles/563809/UIplusDesignplusUsingplusModel-View-Presenter我正在将我的应用转换为异步/等待但遇到问题。

这是一个说明我的问题的例子

Bodies.circle(x, y, 46, {
  render: {
    sprite: {
      texture: 'images/stone.png'
      //Is there a 'width:' or 'height' property?  
    }
  }
});

此代码无法正常等待,并且当抛出异常时,它不会被捕获。这是因为异步无效。当这段代码不是异步/等待时,异常被抓住了。

我知道异步无效是一个不可以除了顶级事件,但我的应用程序的设计方式我真的无法解决这个问题。当我只有一个用户时,我将IView接口更改为

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

并像这样连接起来

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

哪个是hacky但正等待事情并抓住异常。 任何帮助或见解将不胜感激。

1 个答案:

答案 0 :(得分:2)

核心问题是代码使用事件作为策略模式而不是观察者模式。你现在所处的代码并没有太大的作用;适当的重构需要回调接口而不是事件。 E.g:

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

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