Search code examples
.netwinformsmultithreadingmvp

Best Practices for asynchronous calls in MVP with WinForms


I am using the Model-View-Presenter pattern in a WinForms project and one problem (among many) that I am having is when the form tells the presenter to do something and then is un-reactive while the presenter goes of to do it. Fortunately in my project I have no problem with making all presenter calls asynchronous the question is how exactly to do it?

Should each presenter call just be wrapped in a new thread creation?*

new Thread(()=>_presenter.DoSomething()).Start();

What are best-practices here? What if the user presses an "Abort what you're doing" button? How do I abort gracefully?

.* Realistically I would probably just use some sort of a proxy on the presenter to do this rather than putting the thread creation in the WinForm


Solution

  • I can only claim that I've thought about this (prior reading your question ;). First I'd rig the places where this actually matters; for example the DB access chokepoint. If there is a place that should not be executed in the "UI" context (you can save it from http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspx in UI thread and then compare later to non-UI synchronization context) then Debug.BitchAndMoan() about it. Any longer calculations (which "should" be all clearly separated in their own manifolds, right ;) should assert that.

    I guess you should at least make the type of execution of presenter function configurable via attribute which is then obeyed by proxy. (just in case you want something done in serial fashion).

    Canceling a task is actually presenter's problem, but you must have a reference object that tells what you want to stop. If you go the proxy way, then you could pick up created threads into task-list with IAsyncResult's, but it is still a problem to decide which one is supposed to be canceled if same action is allowed to be called multiple times in parallel. So you must supply the task with a suitable call-specific name when you start it; which implies way too much logic into View side -> Presenter should probably ask View to ask user which one of the tasks should be disposed of.

    My experience is that this is usually just worked around by using events (SCSF style). If doing it from scratch, I'd go the proxy way since SCSF has been a pain in so many ways that I doubt its designers' sanity.