2013-09-25 25 views
9

foreach循環搜索完List<>中的每個項目時,我需要觸發回調。異步之後的消防回調任務方法

private async void startSearchBtn_Click(object sender, EventArgs e) 
{ 
    await Search(files, selectTxcDirectory.SelectedPath, status); 
} 

private static async Task Search(List<string> files, string path, Label statusText) 
{ 
    foreach (string file in files) 
    { 
     XmlDocument xmlDoc = new XmlDocument(); 
     xmlDoc.Load(file); 

     statusText.Text = "Started scanning..."; 
     using (XmlReader reader = XmlReader.Create(new StringReader(xmlDoc.InnerXml), new XmlReaderSettings() { Async = true })) 
     { 
      while (await reader.ReadAsync()) 
      { 
       if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "LineName")) 
       { 
        Console.WriteLine(reader.ReadInnerXml()); 
       } 
      } 
     } 
    } 
} 

這是可能的,如果是這樣怎麼辦?

+2

爲什麼不通過委託作爲參數,並調用它在'foreach'循環,你需要?我錯過了什麼嗎? –

+0

http://msdn.microsoft.com/it-it/library/system.asynccallback.aspx – Saturnix

+0

@SriramSakthivel你不會錯過任何東西,這是因爲我不知道傳遞一個委託作爲參數並在foreach循環是8-)你能把這個帖子作爲答案嗎? – jskidd3

回答

16

這很簡單,只需在參數中傳遞一個方法作爲委託。然後在需要的地方調用它。

private async void startSearchBtn_Click(object sender, EventArgs e) 
{ 
    await Search(files, selectTxcDirectory.SelectedPath, status, SearchCompleted); // <-- pass the callback method here 
} 

private static async Task Search(List<string> files, string path, Label statusText, Action<string> callback) 
{ 
    foreach (string file in files) 
    { 
     XmlDocument xmlDoc = new XmlDocument(); 
     xmlDoc.Load(file); 

     statusText.Text = "Started scanning..."; 
     using (XmlReader reader = XmlReader.Create(new StringReader(xmlDoc.InnerXml), new XmlReaderSettings() { Async = true })) 
     { 
      while (await reader.ReadAsync()) 
      { 
       if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "LineName")) 
       { 
        Console.WriteLine(reader.ReadInnerXml()); 
       } 
      } 
     } 

     // Here you're done with the file so invoke the callback that's it. 
     callback(file); // pass which file is finished 
    } 
} 

private static void SearchCompleted(string file) 
{ 
    // This method will be called whenever a file is processed. 
} 
1

由於您使用await,您在startSearchBtn_Click代碼將不會繼續下去,直到Search完成。

所有你需要的是這樣的:

private async void startSearchBtn_Click(object sender, EventArgs e) 
{ 
    await Search(files, selectTxcDirectory.SelectedPath, status); 
    // run your callback here 
} 
2

我編寫它像下面。這樣,您仍然跟蹤待處理任務(_pendingSearch),而startSearchBtn_Click保持同步。

你應該跟蹤未決任務(並且能夠取消它們)。否則,用戶可以連續兩次點擊startSearchBtn併產生兩個搜索任務。在你的情況下,這仍然是一個有效的方案,但通常情況並非如此。

Task _pendingSearch = null; 
private void startSearchBtn_Click(object sender, EventArgs e) 
{ 
    // check if is _pendingSearch != null and still pending here 

    _pendingSearch = Search(files, 
     selectTxcDirectory.SelectedPath, status).ContinueWith((finishedTask) => 
    { 
     // Place your completion callback code here 
    }, TaskScheduler.FromCurrentSynchronizationContext); 
} 

private static async Task Search(List<string> files, string path, Label statusText) 
{ 
    // ... 
} 

將帖子使用await

Task _pendingSearch = null; 
private async void startSearchBtn_Click(object sender, EventArgs e) 
{ 
    // check if is _pendingSearch != null and still pending here 

    _pendingSearch = Search(files, selectTxcDirectory.SelectedPath, status); 
    await _pendingSearch; 
    // Place your completion callback code here 
} 
+0

這比使用await更好嗎? – svick

+1

@svick,我的觀點是不使用防火和忘記的方法,當用戶可以多次點擊這個按鈕。我個人的偏好是沒有'異步無效'事件處理程序專門避免火災和遺忘。儘管如此,有可能跟蹤'async void'方法中的未決任務,我更新了代碼以顯示這一點。 – Noseratio

+1

除了兩段代碼做了一些不同的事情。在你的'ContinueWith()'示例中,_pendingSearch代表了延續。在'await'示例中,它是'Search()''Task'。 – svick