2011-08-04 24 views
5

在我的WPF应用程序中,我需要并行运行2个长时间运行的任务,它们都返回需要在UI中显示的数据。C#.NET任务:如何在多个任务完成时获取通知

我在我的视图模型中有一个名为IsBusy的属性,在两个任务完成之前它应该是true。

如何在2个长时间运行任务完成时获得通知?

我不想使用Task.WaitAll,因为它会阻塞我的UI线程。我不想使用ContinueWith来链接任务,因为我希望这些长时间运行的任务能够并行运行。

回答

4

使用TaskScheduler.FromCurrentSynchronizationContext()并将它传递给TaskFactory.ContinueWhenAll(...)在两个任务完成后执行UI更新。

+0

这正是我要找的。我怀疑在框架中有这样的事情,我无法找到它。 – Mas

0

我认为你的答案是一个回调。

设置长时间运行的线程时,传入对方法的引用。您可以将回调方法传递给任务方法,也可以设置一个AsyncCallback委托实例,该委托内置于代表的BeginInvoke()功能中。

这里有一个基本的例子:

public void StartMyTwoTasks() 
{ 
    //I'm passing the callback to the task method directly; you may prefer to pass it to BeginInvoke() 
    var task1Lambda =()=>Task1(TaskCompleted); 
    var task2Lambda =()=>Task2(TaskCompleted); 

    task1Lambda.BeginInvoke(null,null); 
    task2Lambda.BeginInvoke(null,null); 
} 

public void Task1(Action<int> task1Complete) 
{ 
    //perform your long-running calculation or data retrieval/transformation here 
    Thread.Sleep(10000); 
    //when finished, call the callback method. 
    //You may need to use Control.Invoke() to make sure the callback is executed on the UI thread 
    //If you use the AsyncCallback feature of BeginInvoke/EndInvoke, you don't have to make the call here. 
    taskComplete(1); 
} 

public void Task2(Action<int> taskComplete) 
{ 
    //Ditto 
    Thread.Sleep(8000); 

    taskComplete(2); 
} 

public void Task1Complete(int taskNumber) 
{ 
    TasksComplete[taskNumber-1] = true; 
    If(TasksComplete.All(x=>x==true)) 
     DoSomethingOnceAllTasksAreComplete(); 
} 

使用AsyncCallback的功能,您的回调方法必须符合接受的IAsyncResult的特定委托定义,但你不必担心在正确调用它你的方法;该框架为您处理回调:

public public void StartALongTask() 
{ 
    var taskLambda =()=>PerformTask(); 

    taskLambda.BeginInvoke(TaskComplete,null); 
} 

//one advantage is that you can call a method that returns a value very easily. 
public IEnumerable<string> PerformTask() 
{ 
    //long-running task 
    Thread.Sleep(5000); 

    return Enumerable.Repeat("result", 100); 

    //look ma, no callback invocation. 
    //This makes asynchronous delegates very useful for refactoring a synchronous 
    //operation without a lot of code changes. 
} 

//Here's the callback, which is invoked properly by the runtime when the thread is complete 
public void TaskComplete(IASyncResult ar) 
{ 
    //calling EndInvoke on the same delegate, which is available in the AsyncResult, 
    //returns the return value of that delegate as if you'd called it synchronously. 
    var results = ar.AsyncDelegate.EndInvoke(ar); 

    //Now you can do something with those results. 
} 

这两种模型都应该适合您。其他选项包括设置一个事件,然后在每个方法完成时引发该事件。它会以几乎相同的方式工作,因为事件实际上只是具有一些语法糖的“多播”代表。

0

如何让每个任务对应一个布尔标志以及监视这些标志的另一个单独的观察器线程?当每个任务从处理返回时设置它们相应的标志。然后,监视线程观察标志是否已设置(即两项任务已完成)。如果处理完成,激发事件,将IsBusy设置为false等。

4

一种方法是创建一个第三个线程产生这些任务,并使用Task.WaitAll来延迟线程退出,直到两个任务完成。在该线程结束时,您可以触发事件或执行回调函数。

通过使用BackgroundWorker,您可以更容易,它具有一个名为RunWorkerCompleted的内置事件。这会让你在线程池中,所以你不必担心管理该线程。

3

尝试Task.Factory.ContinueWhenAll。它需要一个数组Tasks,并在所有操作全部完成时异步触发操作。

相关问题