Async / await View Model Presenter winforms

I have a winforms application that uses the MVP pattern as described in this post http://www.codeproject.com/Articles/563809/UIplusDesignplusUsingplusModel-View-Presenter I am converting my application to async / await but I am having problems.

Here's an example to illustrate my problem.

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

      

This code does not expect as expected, and when an exception is thrown it is not caught. This is due to asynchrony. When this code was not asynchronous / pending, exceptions were caught fine.

I know async void is not an exception other than top level events, but the way I design my application. I cannot get around this. When I only had one caller, I changed the IView interface to

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

      

and related things

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

      

This is hacky, but expects as expected and catches exceptions. Any help or understanding would be appreciated.

+3


source to share


1 answer


The main problem is that the code uses events as a strategy template, not an observer template. There isn't as much that you can do with this code as it currently stands; correct refactoring will require callback interfaces, not events. For example:.

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

      



However, there are some workarounds you can apply if this level of refactoring is questionable. I describe such "asynchronous events" on my blog. There are several approaches; it is possible (albeit awkward) to define a Task

return event . My favorite approach is deferral, mainly because deferrals are a concept that WinRT developers already know.

+2


source







All Articles