2009-05-06 49 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); 

取消/放棄然後按鈕連線讓他們告訴任務執行/任務中止。

它實際上比這裏介紹的要複雜一點,但這是一般的想法。