2009-05-06 46 views
7

我在WinForms项目中使用模型 - 视图 - 演示者模式,我遇到的一个问题是当表单告诉演示者做某事然后是当主持人去做这件事的时候,这是不被动的。幸运的是,在我的项目中,使所有演示者调用异步时没有问题,问题是如何执行该操作?在WinForms MVP中异步调用的最佳实践

如果每个主持人的呼叫只是在一个新的线程创建包裹?*

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

什么是这里的最佳实践?如果用户按下“中止你在做什么”按钮怎么办?我如何优雅地放弃?

*现实,我可能只是使用上演示某种代理要做到这一点,而不是把创建线程在WinForm

+0

在这里看到没有真正的参与感到惊讶。我也会对此感兴趣。 – Houman 2009-12-17 12:12:37

回答

2

我只能说我已经考虑过这个问题(事先阅读你的问题;)。首先,我会在这些实际重要的地方进行操作。例如DB访问阻塞点。如果有一个地方不应该在“UI”上下文中执行(您可以在UI线程中将其保存为http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspx,然后再比较非UI同步上下文),然后使用Debug.BitchAndMoan()。任何更长时间的计算(这些“应该”都明确地在他们各自的流派中分开,对;)应该断言这一点。

我想你至少应该通过属性配置演示者函数的执行类型,然后由代理服从。 (以防万一你想以串行方式完成某些事情)。

取消任务实际上是演示者的问题,但您必须有一个参考对象,告诉您要停止的内容。如果使用代理方式,那么您可以使用IAsyncResult的方法将创建的线程提取到任务列表中,但是如果允许同时多次调用同一个操作,那么确定哪一个应该被取消仍然是个问题。所以当你启动它时,你必须提供一个合适的呼叫专用名称;这意味着View方的逻辑太多 - > Presenter可能应该问View来询问用户应该处理哪一个任务。

我的经验是,这通常是通过使用事件(SCSF风格)解决。如果从头开始,我会采用代理方式,因为SCSF在很多方面都非常痛苦,所以我怀疑它的设计师的理智。

+0

在我的应用程序中没有太多的chokepoints问题,只有5或6个不同的地方用户交互被路由到演示者,他们都可以承受异步。如何实际旋转新线程?新线程? BackgroundWorker的?还有别的吗? – 2009-05-06 19:38:39

+1

I _think_ BW对于一个总是做同样事情的已知任务来说意味着更多,所以产卵线程应该是惯用的.NET。根据你做什么你可能想要使用线程池:http://msdn.microsoft.com/en-us/library/ms973903.aspx。默认情况下,线程池的深度是25,所以你可以看看配置/测试(如果你总是产生一个新的线程,这个限制不适用) – 2009-05-06 21:37:02

0

为什么不能让你使用接受一对夫妇回调的代理模式返回结果还是中止?

+0

我很抱歉,但这绝不会回答我的问题。我在问什么是异步运行调用的最佳实践?新线程? BackgroundWorker的?如何专门做一个中止?我不需要担心回调,这是传统的MVP,所以主持人从不实际返回任何东西。 – 2009-05-06 19:18:18

4

我通常把能(现实)不会超过一两秒钟到一个单独的任务的任何行动,是这样的:

public interface ITask 
{ 
    void ExecuteTask (ITaskExecutionContext context); 
    void AfterSuccess(ITaskExecutionContext context); 
    void AfterFailure(ITaskExecutionContext context); 
    void AfterAbortion(ITaskExecutionContext context); 
} 

我也有运行这样的任务的抽象:

public interface ITaskExecutor : IDisposable 
{ 
    void BeginTask(ITask task); 
    void TellTaskToStop(); 
} 

一个本ITaskExecutor的实施方式的使用BackgroundWorker

public class BackgroundTaskExecutor : ITaskExecutor 
{ 
    public void BeginTask(ITask task) 
    { 
     this.task = task; 
     worker = new BackgroundWorker(); 
     worker.DoWork += WorkerDoWork; 
     worker.RunWorkerCompleted += WorkerRunWorkerCompleted; 
     worker.WorkerSupportsCancellation = true; 

     worker.RunWorkerAsync(); 
    } 

    ... 
} 

我非常依赖依赖注入和IoC来将东西连接在一起。在主持人然后我就打电话是这样的:

GoAndDontReturnUntilYouBringMeALotOfMoneyTask task = new GoAndDontReturnUntilYouBringMeALotOfMoneyTask(parameters); 
taskExecutor.BeginTask(task); 

取消/放弃然后按钮连线让他们告诉任务执行/任务中止。

它实际上比这里介绍的要复杂一点,但这是一般的想法。