Я не знаю, насколько «стандартной» является моя идея, но я только недавно начал использовать некоторые асинхронные вызовы с WCF Data Services и Silverlight. В некоторых случаях у нас есть коллекции, которые очень похожи на «коллекции», представленные шаблоном Repository. Мы выдаем запрос для получения элементов из службы данных WCF, но затем каждый возвращаемый элемент должен быть «загружен» по очереди (т. Е. Каждый элемент имеет метод Load, который выполняется асинхронно и может в конечном итоге выдать свой собственный запрос службы данных WCF) , Во время всей этой загрузки любой из наших графических интерфейсов, который зависит от загружаемых данных (определенные вкладки), «блокируется» (отображается индикатор выполнения) до тех пор, пока он не будет загружен. В некоторых случаях нам нужно загрузить две коллекции, потому что одна имеет отношение к другой. Мы используем шаблон обратного вызова с сервисом данных WCF, поэтому после вызова каждого из обратных вызовов (при загрузке нескольких коллекций) мы знаем, что наша задача «загрузки» завершена.
Таким образом, применение нашего шаблона к вашему случаю приведет к чему-то вроде этого (грубый псевдокод с использованием вашего примера кода в качестве отправной точки)
public class FooDataRepository
{
bool fooCompleted = false;
bool barCompleted = false;
int barsSaved = 0;
int barCount = 0;
private MyServiceReferenceClient Client { get; set; }
public void FooClass()
{
Client = new MyServiceReferenceClient();
Client.SaveFooCompleted += Client_SaveFooCompleted;
Client.SaveBarCompleted += Client_SaveBarCompleted;
}
private void Client_SaveFooCompleted(Object sender, EventArgs e)
{
fooCompleted = true;
if (barCompleted)
{
SaveCompleted();
}
}
private void Client_SaveBarCompleted(Object sender, EventArgs e)
{
Interlocked.Increment(barsSaved);
barCompleted = barsSaved == barCount;
if (fooCompleted)
{
SaveCompleted();
}
}
private void SaveCompleted()
{
//Do whatever you want to do when foo and all bars have been saved
}
public void SaveFoo(Foo foo)
{
fooCompleted = barCompleted = false;
barCount = foo.Bars.Count;
barsSaved = 0;
Client.SaveFooAsync(foo);
foreach (var bar in foo.Bars)
Client.SaveBarAsync(bar);
}
}
Если честно, я не уверен, является ли это "хорошим" паттерном или нет. Эти вызовы являются асинхронными и имеют обратный вызов / событие, которое вызывается / вызывается, когда работа завершена. Этот шаблон работает достаточно хорошо, чтобы мы могли отключить индикатор выполнения после загрузки всех данных.
Я мало использовал Задачи и вообще не использовал Rx, поэтому я не знаю, как они относятся к этой проблеме или нет.
Удачи!