Агрегация событий Prism - абонент не сработал - PullRequest
16 голосов
/ 28 ноября 2009

Я работаю над реализацией агрегации событий с помощью Prism. У меня есть несколько модулей, и я хочу, чтобы каждый из них подписывался на события, которые сообщают им, когда они запрашиваются. Я начал делать простой пример с подпиской и издателем в оболочке. Там нет проблем. Сейчас; когда я перемещаю подписчиков на свои модули, они не срабатывают. Что еще более странно, это то, что на самом деле это сработало несколько раз - и все это я ожидал в точке останова. Так что мне кажется, что это какое-то состояние гонки, но я не понимаю почему.

Предположение сделано: Мне не нужно нигде настраивать IEventAggregator - например, регистрация в контейнере IoC? Это встроено в Prism, так что у меня есть только один экземпляр агрегатора событий, верно?

Итак, вопрос заключается в том, как / где / когда я должен настроить своих подписчиков. Есть ли конкретный порядок на вещи и т. Д.? В моем упрощенном примере у меня есть один модуль MyModule. Bootstrapper добавит MyModule в каталог - и инициализирует его:

catalog.AddModule(typeof(MyModule));

MyModule будет хранить агрегатор и использовать его для подписки на MyModuleRequestedEvent. Он также использует реестр меню для регистрации в меню приложения. Идея состоит в том, что в конечном итоге нажатие в меню должно вызвать событие - уведомление MyModule о том, что оно было запрошено. Тогда я хочу, чтобы на MyModule была ответственность, чтобы выяснить, что делать дальше.

public MyModule(IEventAggregator aggregator, IApplicationMenuRegistry menu)
{
    _applicationMenu = menu;
    _aggregator = aggregator;
}

public void Initialize()
{
    var evnt = _aggregator.GetEvent<MyModuleRequestedEvent>();
    evnt.Subscribe(MyModuleRequested);
    _applicationMenu.RegisterMenuItem("MyModule", evnt);
}

public void MyModuleRequested(bool b)
{
    MessageBox.Show("MyModule requested");
}

Теперь у меня в оболочке есть кнопка, которая опубликует это событие. Оболочка получает тот же (?) Агрегатор событий при разрешении.

public Shell(IEventAggregator aggregator)
{
    InitializeComponent();
    var evnt = aggregator.GetEvent<MyModuleRequestedEvent>();
    EventTriggerButton.Click += (s, e) => evnt.Publish(true);
}

Примечания:

  • Подтвердили, что событие опубликовано. Добавление подписчика в оболочку также заставит этого подписчика получить событие.
  • Опять; подписчик в MyModule не запущен. Однако, как ни странно, это было несколько раз.
  • Я не использую ввод для события. Казалось, что вам нужно иметь какой-то тип ввода, поэтому я просто пошел с фиктивным булом. Могу ли я избавиться от этого ..?

Ответы [ 2 ]

30 голосов
/ 28 ноября 2009

Агрегатор событий Prism использует слабые ссылки для связи с событиями. Это необходимо для предотвращения утечек памяти из обработчиков событий.

После запуска инициализатора модуля он удаляется, поэтому ваш обработчик событий уничтожается до его запуска. Вы можете сказать Prism, чтобы он держал обработчик событий, используя перегрузку Subscribe.

evnt.Subscribe(MyModuleRequested, true);

Как шаблон, я склонен помещать любые подписчики событий в отдельный класс и вызывать этот класс из модуля Initialize метода. Таким образом, события остаются живыми, но разделяются, пока модуль все еще уничтожен.

2 голосов
/ 28 ноября 2009

Итак, я только что получил теорию, но сейчас нет времени проверять ее ... Завтра сделаю.

Вопрос. Поддержит ли их добавление модулей в ModuleCatalogue? Я предполагал, что так и будет. Следовательно - MyModule должен остаться в живых - и затем будет запущен, когда событие будет опубликовано.

protected override IModuleCatalog GetModuleCatalog()
{
    var catalog = new ModuleCatalog();
    catalog.AddModule(typeof(MyModule));
    return catalog;
}

Однако, если это не поддерживает работу модуля, очевидно, что ему будет сложно отреагировать на событие. Объект-модуль умирает, но он не отписывается - поэтому я увижу подписчика в списке EventAggregator, но подписчика больше нет. Также; Я упомянул, что на самом деле это иногда срабатывает, что было бы, если бы сборщик мусора не успел вынести мусор до того, как событие будет запущено.

Похоже ли это на случай? Если так - я еще не подумал о решении, так что вы можете предложить его в другой ветке ответов.

Итак, что такое ModuleCataloge в любом случае? Просто список хранится для инициализации, а затем выбрасывается?

...