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.
source to share
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.
source to share