#wpf #events #asynchronous #delegates #prism
#wpf #Мероприятия #асинхронный #делегаты #призма
Вопрос:
Предполагая, что у вас есть папка электронной почты и сообщения в ней. Каждое сообщение имеет свойство Body, которое должно загружаться асинхронно и уведомлять вас о завершении, как бы вы подошли к этому?
1 — Сообщение.LoadBody() сообщение о событии.BodyLoadComplete
2 — Сообщение.LoadBody(действие завершено)
Для полноты картины задействованы WPF и Prism.
Спасибо!
Редактировать:
Сообщение будет объектом пользовательского интерфейса, который обернет интерфейс iMessage (который не готов к пользовательскому интерфейсу (нет INPC)), поэтому причина, по которой я спрашиваю, заключается в том, что мы должны согласиться на интерфейс между пользовательским интерфейсом и бизнес-уровнем.. iMessage. (Бизнес-уровень будет использовать библиотеку Imap, которая уже имеет некоторый асинхронный шаблон, но мы не хотим слишком сильно зависеть от какого-либо imp, поэтому я пытаюсь найти лучший интерфейс..
Комментарии:
1. Более описательным и открытым заголовком может быть «Лучший шаблон для асинхронных методов?»
2. я не обсуждаю шаблоны aync, плюс в таком потоке это всегда заканчивается «зависит от того, что вы делаете»
Ответ №1:
Если вы используете .NET 4, я бы использовал:
Task<string> LoadBodyAsync()
(Возможно, вы захотите реализовать это с помощью TaskCompletionSource<TResult>
.)
Затем вызывающий может добавлять продолжения и т. Д., Как они пожелают … и самое главное, в дивном новом мире .NET 4.5 и C # 5 это будет работать без проблем с async
/ await
features .
Комментарии:
1. Внутри тела загрузки вызывается другая библиотека imap, которая выполняет загрузку в другой поток, поэтому использование Task тоже было моей первой идеей, но в данном случае это не совсем вариант..
2. @Zapacila: Почему нет? Высказывание «это не вариант» точно не дает много информации.
3. @Joe было бы 2 потока, один из которых был создан задачей, а 1 — библиотекой inap..
4. @Zapacila: Не обязательно. Я не предлагал использовать
Task.Factory.StartNew
— я предложил использоватьTaskCompletionSource<TResult>
. Вы можете установить результат для источника завершения задачи после завершения операции IMAP.5. @Joe Awesoomeрешение, я виноват в том, что забегаю вперед. Я прочитал больше о TaskCompletionSource на blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx и это совпадение. Теперь интерфейс iMessage может иметь другие события при изменении данных, должны ли мы смешивать эти 2 разные парадигмы?
Ответ №2:
Из ваших двух вариантов:
Message.LoadBody() // Plus an event, Message.BodyLoadComplete
// or ...
Message.LoadBody(Action completeDelegate)
Опция события является более гибкой и иногда может быть менее болезненной в использовании. Если вам все равно, когда или если LoadBody
завершается, то вы не обязаны предоставлять поддельный обратный вызов. И вы можете привязать событие завершения к нескольким обработчикам событий, что иногда может быть полезно (например, если необходимо обновить несколько элементов управления пользовательского интерфейса).
Однако оба ваших решения нетипичны. Типичный «старый» способ сделать это — LoadBody
разделить на BeginLoadBody
и EndLoadBody
и предоставить пользователю IAsyncResult
. См. Эту статью. Типичный «новый» способ сделать это изложен в ответе Джона Скита.
Ответ №3:
Если вы используете Prism, вам следует рассмотреть возможность использования EventAggregator и публикации сообщения, чтобы указать, что почта загружена. Это позволит вам легко иметь несколько слабо связанных подписчиков для этого «события».
Использование EventAggregator является элегантным решением для публикации событий и приводит к гораздо более чистой и развязанной архитектуре, которую легче расширять. Например, если вы хотите добавить новую функцию к загрузке электронной почты, такую как индикация хода выполнения, вы можете просто подписаться на EmailLoaded
сообщение, и все готово, вам не нужно жестко связывать ваш новый компонент с электронными письмами через событие или обратный вызов, им не нужно знать друг о друге.