8

我在 WinForms 项目中使用 Model-View-Presenter 模式,我遇到的一个问题(在许多问题中)是当表单告诉演示者做某事,然后在演示者去做时没有反应。幸运的是,在我的项目中,让所有演示者调用异步都没有问题,问题是如何做到这一点?

是否应该将每个演示者调用都包含在一个新的线程创建中?*

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

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

.* 实际上,我可能只是在演示者上使用某种代理来执行此操作,而不是将线程创建放在 WinForm 中

4

3 回答 3

5

我通常将任何可能(实际上)花费一两秒以上的操作放入单独的任务中,例如:

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

然后连接取消/中止按钮,以便它们告诉任务执行器/任务中止。

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

于 2010-09-06T09:09:55.017 回答
2

我只能声称我已经考虑过这一点(在阅读您的问题之前;)。首先,我会安装这实际上很重要的地方;例如数据库访问阻塞点。如果在“UI”上下文中存在不应该执行的地方(您可以从http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspx在 UI 线程中保存它然后稍后与非 UI 同步上下文进行比较)然后 Debug.BitchAndMoan() 关于它。任何更长的计算(“应该”在它们自己的流形中都清楚地分开,对;)应该断言。

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

取消任务实际上是演示者的问题,但您必须有一个参考对象,告诉您要停止什么。如果您采用代理方式,那么您可以使用 IAsyncResult 将创建的线程拾取到任务列表中,但是如果允许并行调用多次相同的操作,则决定取消哪个线程仍然是一个问题。因此,您必须在启动任务时为任务提供合适的特定于调用的名称;这意味着 View 方面的逻辑太多 - > Presenter 可能应该要求 View 询问用户应该处理哪一项任务。

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

于 2009-05-06T19:31:49.363 回答
0

为什么不让您使用的代理模式接受几个回调以返回结果或中止?

于 2009-05-06T19:09:30.557 回答