2012-05-18 231 views
1

我有2個異步進程,需要被依次調用(一個是XML創建backgroundworker,另一個是使用在第一個進程中創建的XML文件的raring BW)。這些線程的主要原因是阻止UI凍結並通過進度條提供狀態更新 - 因爲這樣的同步方法不可取/可能。等待BackgroundWorker完成?

if (!CreateXMLBW.IsBusy) 
{ 
CreateXMLBW.RunWorkerAsync(""); 
} 
if (!CreateRarBW.IsBusy) 
{ 
CreateRarBW.RunWorkerAsync(); 
}

我不能把第二BW第一的完成事件中的過程可以單獨使用,因此,如果我只是想創建的XML文件,我可以做到這一點。

我試過使用AutoResetEventWaitOne但這(無論什麼原因)仍然無法正常工作。

是否有任何其他方式可以等待BW完成而不凍結主UI線程?

+0

爲什麼你不創建一個新的工人同步運行這兩個工人?你運行這個新的工作異步 – Fabske

+0

我喜歡這個想法,但反對幹。 –

+0

它很乾燥,您不需要重複使用其他兩名工作人員的代碼。無論如何,下面提出的任務解決方案更加優雅:) – Fabske

回答

1

您的場景正是Task的設計目的。在您的特定情況下,你的代碼可能是這樣的:

public delegate void UpdateUI(int progress); 

private void RunOneAfterAnotherAsync() 
{ 
    Task<XmlElement> task = Task.Factory.StartNew<XmlElement>(CreateXMLBW); 
    task.ContinueWith(CreateRarBW); 
} 

private XmlElement CreateXMLBW() 
{ 
    // your code 

    // progress 
    progressBar1.Invoke((UpdateUI)UpdateProgressBar, new object[] {progressValue}); 

    // result 
    XmlDocument doc = new XmlDocument(); 
    return doc.CreateElement("element"); 
} 

private void CreateRarBW(Task<XmlElement> task) 
{ 
    CreateRarBW(task.Result); 
} 

private void CreateRarBW(XmlElement arg) 
{ 
    // your code 
} 

public void UpdateProgressBar(int value) 
{ 
    this.progressBar1.Value = value; 
} 

RunOneAfterAnotherAsync是不會阻止你的2種方法異步運行此起彼伏。 CreateRarBW僅在CreateXMLBW結束時纔會運行,但您可以使用ContinueWith中的其他參數更改該參數。

你可以做得比這個例子更多 - 我鼓勵你去探索Task這個類。

EDIT

我有擴展示例一點點地結合來自第一任務到第二個被傳遞的結果。還添加了UI進度示例。

+0

我可以在沒有交叉線程異常的情況下從任務中報告進度條的進度或類似情況嗎? –

+1

要報告進度,您需要在任務中調用某個委託。如果你想直接從任務更新UI,你必須使用Control.Invoke。 –

+0

添加了進度示例代碼。 –

1

如果你不想等待,直到事件(所以我你會做什麼)塊UI 你可以在DoWork()結束觸發事件,並且UI線程會接受它。

如果您使用的是4.0並且可以避免使用BackgroundWorker,則可以使用TPL的Task.ContinueWith

一個可能看起來像這樣:

Action action =(() => DoWorkMethod()); 
    Task.Factory.StartNew(() => action()).ContinueWith(()=>CallAfterComplete()); 
1

你也可以在這個例子中使用Task,如:

class Program 
{ 
    static XElement CreateXml() 
    { 
     System.Threading.Thread.Sleep(1000); 
     return XElement.Parse(@"<FooBar>Hi!</FooBar>"); 
    } 

    static void ProceedXml(XElement xml) 
    { 
     System.Threading.Thread.Sleep(1000); 
     Console.WriteLine(xml.ToString()); 
    } 

    public static void Main() 
    { 
     Task.Factory.StartNew<XElement>(CreateXml) 
        .ContinueWith(t => ProceedXml(t.Result)); 
     Console.ReadKey(); 
    } 
} 
0

你的UI可以在第一BW處理RunWorkerCompleted事件調用第二個BW。

+0

正如我的問題 - 「我不能把第二個BW放在第一個完成事件中,因爲這些過程可以單獨使用,因此如果我只是想創建XML文件,我可以做到這一點。」這意味着如果我把它放在RunWorkerCompleted事件中,它總是會觸發,這是我不想要的。 –

+0

@Myles好的,但是我認爲你的UI會知道它是否想運行第二個BW。我並不是說你會運行它。 – Martin