2013-09-05 1 views
4

У меня есть проблема, как ждут метод асинхронных в методах жизненного цикла WPF (с рамками Caliburn-Micro) (например, OnActivate, OnInitialized, OnExit -., Который связан непосредственно с Application.Exit события)Почему приложение Application.Exit работает, даже если обработчик является асинхронным в жизненном цикле приложений WPF?

Этих статья точно описывает мою проблему: http://mark.mymonster.nl/2013/07/10/donrsquot-make-your-application-lifetime-events-async-void (теперь я думаю о том, чтобы использовать решение этой статьи, но, похоже, немного перехитрил для первого взгляда)

Мне нужно дождаться некоторых методов асинхронизации в моем ящике OnExit, поэтому у меня есть это как асинхронный. И это работает. Вид. Я не понимаю почему ??, но при вызове события Application.Exit он как-то ждет, пока метод не будет завершен, даже если обработчик будет асинхронным. Можете ли вы объяснить, как это возможно? И это безопасно? Или это просто совпадение? Async void следует использовать только для Топ- событий, это тот случай?

Я просмотрел код системы. И связывания выглядит следующим образом:

public event EventHandler Exit 
{ 
    add 
    { 
    XcpImports.CheckThread(); 
    this.AddEventListener(DependencyProperty.RegisterCoreProperty(20053U, (Type) null), (Delegate) value); 
    } 
    remove 
    { 
    XcpImports.CheckThread(); 
    this.RemoveEventListener(DependencyProperty.RegisterCoreProperty(20053U, (Type) null), (Delegate) value); 
    } 
} 

который действительно загадочное, и я не могу увидеть, что на самом деле происходит в .NET Framework, вызвав это событие.

Что так же странно, что вызов ждут Task.Delay (1) в обработчик вызывает ТУПИК, когда я не использую ConfigureAwait (ложь). Поэтому я бы сказал, что есть где-то .Wait() используется глубоко в .net-коде.

Примечание: когда я делаю OnActivate, OnInitialized обработчики async, как и ожидалось, страница не дожидается завершения обработчика.

Thx для ваших ответов!

ответ

8

Теоретически возможно, чтобы структура обнаружила использование async void и дождалась возврата метода async void. Я описываю детали в своем article on SynchronizationContext. AFAIK, ASP.NET - единственная встроенная инфраструктура, которая будет ждать обработчиков async void.

WPF делает не имеет специальную обработку для методов async void. Так что факт, что ваш обработчик выхода заканчивается, - это просто совпадение. Я подозреваю, что операции, которые вы делаете await, либо уже завершены, либо очень быстро, что позволяет вашему обработчику выполнить синхронно.

При этом я не рекомендую решение в статье, на которую вы ссылались. Вместо этого обработайте событие Closing окна, откройте все асинхронное сохранение, которое вам нужно сделать, и отмените команду закрытия (а также подумайте о скрытии окна сразу). Когда асинхронная операция будет завершена, закройте окно еще раз (и позвольте ему закрыть это время). Я использую этот шаблон для выполнения асинхронных «закрытых» анимаций на уровне окна.

Я не могу воспроизвести тупик, который вы описываете. Я создал новый .NET 4.5 WPF приложения и добавил обработчик выхода как такового:

private async void Application_Exit(object sender, ExitEventArgs e) 
{ 
    await Task.Delay(1); 
} 

но не наблюдали в тупик.На самом деле, даже с использованием Task.Yield, ничто после того, как await никогда не исполнялся, что я и ожидал.

+0

Я создал также новое приложение WPF и не смог воспроизвести тупик. После некоторого расследования я узнал, что это было вызвано нашей библиотекой регистрации, которая поддерживала приложение «живым», и именно поэтому OnExit был закончен. Фактически ** тупик действительно происходит **, но без этого компонента протоколирования вы его не видите, так как он * убит * сразу после закрытия приложения. Ваш шаблон для закрытия приложения звучит превосходно, я сделаю это! Но почему бы вам не рекомендовать решение из этой статьи? Мне все еще нужно, как ждать чего-то, например, в методе OnActivate. Такой помощник облегчит мою жизнь :) –

+0

Код в этой статье (и ответы на него) не совсем корректен; IIRC не обрабатывает исключения правильно. Есть тонна * нюансов в том, что вы делаете это правильно, и даже если у вас есть отличная реализация, она все еще не может * работать в любой ситуации. [Стивен Туб имеет лучшее резюме этих хаков] (http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx); обратите внимание, что каждый описанный хак имеет серьезный недостаток. Не существует «одного решения», которое работает повсеместно. –

+0

Лучшим решением является поиск альтернатив, например, 'await' в' OnActivate', скорее всего, асинхронная инициализация некоторого состояния, используемого для отображения (т. Е. ViewModel); правильным решением в этом случае является использование чего-то типа [асинхронного шаблона инициализации] (http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html), который я описываю в своем блоге. Обратите внимание, что это правильное решение * * больше работы: вам нужно преднамеренно спроектировать состояние пользовательского интерфейса для «загрузки», а затем переход, когда завершение инициализации async завершено. –