2012-05-18 236 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