Ответ 1
По умолчанию, когда вы await
a Task
, который еще не завершен, метод возобновляется в захваченном контексте (в данном случае контексте пользовательского интерфейса).
Итак, вот почему ваш код не работает:
-
OnLaunched
вызываетLoad
(в контексте пользовательского интерфейса). -
Load
ждет. Это заставляет методLoad
возвращать неполную задачу и планировать ее завершение позже. Это продолжение запланировано для контекста пользовательского интерфейса. -
OnLaunched
блокирует задачу, возвращенную изLoad
. Это блокирует поток пользовательского интерфейса. -
GetFileAsync
в конечном итоге завершает работу и пытается запустить продолжение дляLoad
. - Продолжение для
Load
ожидает, что поток пользовательского интерфейса будет доступен, чтобы он мог выполняться в контексте пользовательского интерфейса. - В этот момент
OnLaunched
ожидает завершенияLoad
(блокируя поток пользовательского интерфейса, делая это), аLoad
ожидает, что поток пользовательского интерфейса будет бесплатным. Тупик.
Эти лучшие практики избегают этой ситуации:
- В методах
async
используйтеConfigureAwait(false)
, когда это возможно. В вашем случае это изменитawait folder.GetFileAsync("filename.xml");
наawait folder.GetFileAsync("filename.xml").ConfigureAwait(false);
. - Не блокировать
Task
s; онasync
полностью вниз. Другими словами, заменитеWait
наawait
.
Для получения дополнительной информации:
- Ожидание, и пользовательский интерфейс, и взаимоблокировки! О, мой!
- My
async
/await
intro post, который включает краткое описание того, какTask
awaiters используютSynchronizationContext
и представляет несколько лучших практик. - Часто задаваемые вопросы по асинхронному подключению/оживанию, в котором более подробно рассматриваются контексты.
- Этот форум MSDN.
- Stephen Toub демонстрация этого тупика, и так делает Люциан Вишик.
Обновление, 2012-07-13: Включить этот ответ в сообщение в блоге.