Получить представление об асинхронном кодировании нелегко, особенно когда есть некоторая последовательная зависимость между одной операцией и следующей. Это именно та проблема, которую я написал для обработки AsyncOperationService
, это очень короткий кусочек кода.
Первое небольшое легкое чтение для вас: Простой асинхронный оператор Runner - часть 2 . Непременно прочитайте часть 1, но она немного тяжелее, чем я хотел. Все, что вам действительно нужно, это AsyncOperationService
код из него.
Теперь в вашем случае вы должны преобразовать код извлечения во что-то вроде следующего.
private IEnumerable<AsyncOperation> FetchItems(int startId)
{
XDocument itemDoc = null;
int currentId = startId;
while (currentID != 0)
{
yield return DownloadString(new Uri(String.Format("http://SomeURL/{0}.xml", currentId), UriKind.Absolute),
itemXml => itemDoc = XDocument.Parse(itemXml) );
// Do stuff with itemDoc like creating your item and placing it in the list.
// Assign the next linked ID to currentId or if no other items assign 0
}
}
Обратите внимание, что в блоге также есть реализация DownloadString
, которая, в свою очередь, использует WebClient, что упрощает работу. Однако принципы все еще применяются, если по какой-то причине вы должны придерживаться HttpWebRequest. (Дайте мне знать, если у вас возникли проблемы при создании AsyncOperation
для этого)
Затем вы использовали бы этот код следующим образом: -
int startId = GetSomeIDToStartWith();
Foo myFoo = new Foo();
myFoo.FetchItems(startId).Run((err) =>
{
// Clear IsBusy
if (err == null)
{
// All items are now fetched continue doing stuff here.
}
else
{
// "Oops something bad happened" code here
}
}
// Set IsBusy
Обратите внимание, что вызов Run
является асинхронным, выполнение кода будет перепрыгивать через него до того, как будут выбраны все элементы. Если пользовательский интерфейс бесполезен для пользователя или даже опасен, вам необходимо заблокировать его дружественным способом. Лучший способ (IMO) сделать это с помощью элемента управления BusyIndicator
из набора инструментов, установить его свойство IsBusy
после вызова на Run
и очистить его в обратном вызове Run
.