2013-05-20 113 views
0

在wp8中排列複雜任務的正確方法是什麼?wp8的任務隊列?

任務由以下部分組成:

  1. 顯示一個ProgressIndicator通過更新模型變量
  2. 提取或將數據存儲到WCF服務(UploadStringAsync
  3. 更新潛在數據綁定模型,其結果從UploadStringCompleted
  4. 通過更新變量

目前,我已經工作了一類擁有命令對象的隊列,在運行時添加的項目已啓動一個單獨的線程模型隱藏ProgressIndicator如果它尚未運行。

但是,我有等待代碼停止運行的任務或子任務的問題。

此前我已經使用異步等待,但行爲的幾個級別變得越來越難以預測。

我想要的是主線程能夠創建和排隊命令對象。 命令對象應該一次運行一個,直到前一個完全結束才啓動一個新對象。 命令對象應該能夠使用調度程序訪問主線程(如果有必要)。

+0

'BlockingCollection'? – I4V

回答

6

如果您使用的是async/await,則不需要另一個線程(因爲您沒有CPU綁定處理)。

就你而言,這聽起來像你只需要一個異步委託隊列。異步委託的自然類型是Func<Task>(沒有返回值)或Func<Task<T>>(具有返回值)。不幸的是,這個小技巧在這一點上並不爲人所知。

因此,申報異步委託隊列:

private readonly Queue<Func<Task>> queue = new Queue<Func<Task>>(); 

然後你就可以有一個單一的「頂級」的任務,只是(異步)處理隊列:

private Task queueProcessor; 

queueProcessor只要沒有更多的物品,可以是null。只要它不是null,它會代表這個方法:然後

private async Task ProcessQueue() 
{ 
    try 
    { 
    while (queue.Count != 0) 
    { 
     Func<Task> command = queue.Dequeue(); 
     try 
     { 
     await command(); 
     } 
     catch (Exception ex) 
     { 
     // Exceptions from your queued tasks will end up here. 
     throw; 
     } 
    } 
    } 
    finally 
    { 
    queueProcessor = null; 
    } 
} 

Enqueue方法是這樣的:現在

private void Enqueue(Func<Task> command) 
{ 
    queue.Enqueue(command); 
    if (queueProcessor == null) 
    queueProcessor = ProcessQueue(); 
} 

,我有異常處理設置是這樣的:任何排隊拋出異常的命令將導致隊列處理器停止處理(具有相同的異常)。這可能不是您的應用程序的最佳行爲。

您可以使用這樣的(帶有一個lambda或實際的方法,當然):

Enqueue(async() => 
{ 
    ShowProgressIndicator = true; 
    ModelData = await myProxy.DownloadStringTaskAsync(); 
    ShowProgressIndicator = false; 
}); 

注意使用DownloadStringTaskAsync。如果你write TAP wrappers for your EAP members,你的async代碼將更「自然」(即更簡單)。

這是非常複雜,我建議你把它變成一個單獨的類,但你要決定如何處理(和麪)錯誤第一。

+0

我想知道會發生什麼,如果我將足夠的暫停兩次調用Enqueue,以便第一個命令已經出隊並等待。 –

+0

好抓! Enqueue中的檢查應該用於'queueProcessor',而不是'queue.Count'。我已經更新了答案中的代碼。 –

+0

我試圖用這種類型的工作隊列實現暫停/恢復,這樣在應用程序關閉時我可以暫停並堅持數據庫,或者讓用戶有機會等待,並因此恢復處理。 雖然讓它工作起來很麻煩。取消是命中與遺漏,並且恢復_queueprocessor = ProcessQueue()不像Enqueue()中那樣工作。 很高興聽到別人會怎麼做呢? – FrugalTPH