您可以使用TaskFactory.ContinueWhenAll http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.continuewhenall%28v=vs.100%29.aspx构建一个在输入任务全部完成时运行的延续。
Task[] tasks = new Task[3]
{
LoadTools(),
LoadResources(),
LoadPersonel()
};
Task.Factory.ContinueWhenAll(tasks, t =>
{
DataView = CollectionViewSource.GetDefaultView(Data);
DataView.Filter = FilterTimelineData;
IsBusy = false;
}, CancellationToken.None, TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
请注意,如果您使用 C# 5,这会变得更简单await
/async
syntax:
private async void LoadData()
{
SetBusy("Loading...");
Data.Clear();
Task[] tasks = new Task[3]
{
LoadTools(),
LoadResources(),
LoadPersonel()
};
await Task.WhenAll(tasks);
DataView = CollectionViewSource.GetDefaultView(Data);
DataView.Filter = FilterTimelineData;
IsBusy = false;
}
但是,如果我从服务方法返回延续任务,则永远不会调用延续任务,并且 WaitAll 会永远等待
问题是您的延续任务需要 UI 线程,并且您正在阻塞 UI 线程WaitAll
称呼。这会造成一个无法解决的僵局。
修复上述问题应该可以纠正这个问题 - 您需要将延续作为任务返回,因为这就是您需要等待完成的内容 - 但是通过使用TaskFactory.ContinueWhenAll
您释放 UI 线程,以便它可以处理这些延续。
请注意,这是 C# 5 简化的另一件事。您可以将其他方法编写为:
internal static async Task LoadResources(Action<IEnumerable<Resource>> completedCallback, Action<Exception> errorCallback)
{
try
{
await Task.Run(() =>
{
//... get resources from somewhere
return resources;
});
}
catch (Exception e)
{
errorCallback(task.Exception);
}
completedCallback(task.Result);
}
话虽这么说,通常最好编写返回一个的方法Task<T>
而不是提供回调,因为这简化了两端的使用。