2016-12-06 104 views
0

讓我們先從代碼:C#等任務,而不阻塞UI

private void StartStopService() 
{ 
    var task = Task.Run(() => debugService.Iterate()); 
    StartStopInit(true); 

    //task.Wait(); 
    if (task.IsCompleted) 
     StartStopInit(false); 
} 

我試圖做一個計劃,將通過一個同時不阻塞UI線程中執行的給定的DLL的從DB一個列表。提供的方法在按鈕單擊時運行,它正在啓動一個任務來遍歷DLL。

public void Iterate() 
{ 
    foreach (var plugin in runningPlugins) 
     ExecutePlugin(plugin); 
} 

Execute方法只是一個一個執行DLL。

我需要一個解決方案,在所有DLL完成執行後運行StartStopInit()方法。如果我把task.Wait()我會阻止UI ...情況,因爲它現在當然不會工作,因爲如果任務啓動時條件通過。如果我執行某種無限循環來監聽更改,我將再次阻止UI。我該如何解決這個問題?

+0

如果您不阻止用戶界面,您是否認爲您可能能夠在其執行過程中再次啓動該操作?我的意思是,如果在按鈕上調用了「StartStopService」,是否考慮過在這種情況發生時是否需要禁用按鈕? –

+2

現在在異步/等待世界中的正常方式是將你的方法標記爲「async Task」(而不是'void'),並使用'await task;'等待任務完成。請注意我之前對不阻止用戶界面的評論。 –

+0

那麼最終的想法是轉發按鈕點擊取消令牌如果任務仍在執行 – Norgul

回答

4

如果可以,您應該移動到新的async/await關鍵字和周圍的支持。

對於你的問題的特定代碼,這裏就是我會做:

  1. 標記方法async Task要清楚調用代碼,這種方法是異步
  2. 使用await在裏面的任務該方法停止執行,並「等待」的任務繼續

具體來說之前完成,這是它會是什麼樣子:

private async Task StartStopService() 
{ 
    StartStopInit(true); 
    await Task.Run(debugService.Iterate); 
    StartStopInit(false); 
} 

時序方面我會告訴周圍的代碼,該方法現在正在執行產卵子任務之前執行。

也考慮添加try/catch塊,如果子任務拋出異常會發生什麼?

private async Task StartStopService() 
{ 
    try 
    { 
     StartStopInit(true); 
     await Task.Run(debugService.Iterate); 
    } 
    catch (InvalidOperationException ex) 
    { 
     // What to do here??? 
    } 
    finally 
    { 
     StartStopInit(false); 
    } 
} 
+0

這很好用!我怎樣才能給它一個變量名? 'var task = await ...'不起作用?我想轉發一個取消標記 – Norgul

+0

要轉發取消標記,必須將其作爲參數的一部分發送,如果任務返回某些內容,即。它被定義爲'任務'其中'T'是某種類型,那麼你可以使用'var result = await task'來等待任務並獲得結果,但是如果它只是'Task',那麼你只能等待它完成。但是,再次,必須將取消標記作爲參數提供給該方法。 –

+0

我知道,但爲了做到這一點,我需要將任務註冊爲變量,以瞭解它是否正在運行?我試着用'var task = new Task(()=> ..'),但是如果我做'等待任務',它不會啓動。 '等待task.Start()'拋出錯誤...編輯...明白了,nvm,謝謝:) – Norgul