Prism コードサンプル学習：14-UsingEventAggregator

# Prism コードサンプル学習：14-UsingEventAggregator

## はじめに

以下の記事の続きです。
<https://qiita.com/mngreen/items/787f8f92e2da3c787770>

## 14-UsingEventAggregator

本サンプルは、互いに依存していないモジュール間でメッセージを送受し、連携して動作することを確認するサンプルとなっています。

UsingEventAggregator.Coreではモジュール間で共通して利用されるMessageSentEventクラスを定義しています。

```cs
using Prism.Events;

namespace UsingEventAggregator.Core
{
    public class MessageSentEvent : PubSubEvent<string>
    {
    }
}
```

[PubSubEvent\<T\>](https://github.com/PrismLibrary/Prism/blob/2b9873d9a6595c1f50ca9e6f6605d0bb82b0ea5f/src/Prism.Core/Events/PubSubEvent.cs#L140)は[EventBase](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventBase.cs#L24)クラスを継承していて、内部的には購読者をコレクションとして保持していることがわかります。

[Subscribeの実処理](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/PubSubEvent.cs#L71)では、まずはじめに[ActionReference](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/DelegateReference.cs)を生成しています。渡されたアクションからそのアクションの持ち主であるインスタンスを特定しています。
その後、それぞれのオプションによって生成されるインスタンスが異なりますが、基本的に利用されそうな[EventSubscription](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventSubscription.cs)クラスでは、必要に応じてアクションを実行するか否かを決める処理（[GetExecutionStrategy](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventSubscription.cs#L156)）が重要そうでした。
上記のメソッドがどこで利用されるかというと、EventBaseクラスの[InternalPublish](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventBase.cs#L57)メソッド内にあるPruneAndReturnStrategiesメソッドです。この中で実行対象が抽出されます。

上記のイベントをModuleAは発行、ModuleBは購読しているのが以下のコードです。

```cs
namespace ModuleA.ViewModels
{
    public class MessageViewModel : BindableBase
    {
        IEventAggregator _ea;

        private string _message = "Message to Send";
        public string Message
        {
            get { return _message; }
            set { SetProperty(ref _message, value); }
        }

        public DelegateCommand SendMessageCommand { get; private set; }

        public MessageViewModel(IEventAggregator ea)
        {
            _ea = ea;
            SendMessageCommand = new DelegateCommand(SendMessage);
        }

        private void SendMessage()
        {
            // イベントアグリゲーターからイベントを取得してメッセージを発行する
            _ea.GetEvent<MessageSentEvent>().Publish(Message);
        }
    }
}

namespace ModuleB.ViewModels
{
    public class MessageListViewModel : BindableBase
    {
        IEventAggregator _ea;

        private ObservableCollection<string> _messages;
        public ObservableCollection<string> Messages
        {
            get { return _messages; }
            set { SetProperty(ref _messages, value); }
        }

        public MessageListViewModel(IEventAggregator ea)
        {
            _ea = ea;
            Messages = new ObservableCollection<string>();

            // イベントアグリゲーターを経由して、イベントを購読している
            _ea.GetEvent<MessageSentEvent>().Subscribe(MessageReceived);
        }

        private void MessageReceived(string message)
        {
            Messages.Add(message);
        }
    }
}

```

[EventAggregator](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Events/EventAggregator.cs)では型をキー、イベントをバリューとするディクショナリーを保持しており、要求に応じてイベントを返します。
EventAggregator自体は全体で46行ほどしかなく、GetEvent\<TEventType\>メソッドを公開しているのみで非常にシンプルな作りになっています。

## おわりに

今回はEventAggregatorの使い方と、そのライブラリ内部の実装を読んでみました。
EventAggregatorを利用することで、結合が疎であるモジュール間でもうまく連携できそうです。
また、APIをシンプルに保つための工夫として、Actionの持ち主であるインスタンスを引数にわたすのではなく、Actionからインスタンスを探し出す方法を採用しているのは、勉強になりました。
次回、[15-FilteringEvents](https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/15-FilteringEvents)について見ていこうと思います。