13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Prism入門 その5 - IEventAggregator

Last updated at Posted at 2018-05-25

はじめに

Prism入門5回目です。
今回もVMからVに通知する方法について説明します。

前回はVMからVに通知してダイアログを表示する方法のみを話しました。
予め設定されているダイアログは表示できますが、それ以外はできません。
エラー表示だけならそれで十分ですが、実際には広告や起動時のヘルプの表示など、
好きなようにVMからVを操作できるようにする必要が出てきます。

Prismでは任意の操作をVMからVに行うために、EventAggregatorという機能があります。

EventAggregator

EventAggregatorは今までと同じように、
コンストラクタにIEventAggregator eventAggregatorを記述することで使用できるようになります。
今までと異なり、ViewModelのクラスにだけでなくViewのクラスにも引数を記述します。

Viewには可能な限りソースコードを書かないのが望ましいですが、書かないとVMからVへの操作を行えないので、仕方がなく書きます。

EventAggregatorはVMでメッセージを送信し、Vでメッセージを受信してイベントを発生させることでVMからVの操作を実現しています。

VMではボタンをクリックするとEventAggregatorを通じてメッセージをVに通知するようにします。
メッセージを通知するにはeventAggregator.GetEvent<T>().Publish(S);を使用します。
Tのクラスを引数Sのコンストラクタで初期化して、Tのインスタンスを送信します。

TのクラスはEventBaseを継承する必要があります。
ただ、簡単に使うだけなら予め定義されているPubSubEventを使用するのが楽です。

VMの例です。PubSubEventを「Publish!」という文字列で初期化して送信します。

VM

using Prism.Events; // IEventAggregatorはPrism.Eventsで定義されている

...

public DelegateCommand Clicked { get; private set; }

public MainPageViewModel(IEventAggregator eventAggregator)
{
    Clicked = new DelegateCommand(() => {
       eventAggregator.GetEvent<PubSubEvent<string>>().Publish("Publish!");
    });
}

メッセージはVで受信します。
受信する方法を定義するにはeventAggregator.GetEvent<T>().Subscribe(S);を使用します。
Tのクラスが送信された時に受信してSのメソッドを実行します。Sのメソッドの引数にはVMのPublish("Publish!")で指定した引数が渡されます。
今回のサンプルでは「Publish!」という文字列が渡されます。

指定したメソッドでは渡された文字列をダイアログとして表示します。

V

using Prism.Events; // IEventAggregatorはPrism.Eventsで定義されている

...

public MainPage(IEventAggregator eventAggregator)
{
    InitializeComponent();

    eventAggregator.GetEvent<PubSubEvent<string>>().Subscribe(ShowMessage);
}

void ShowMessage(string message)
{
    DisplayAlert("Subscribe", message, "OK");
}

前回より記述は長くなりましたが独自に記述したソースコードでVMからVを操作できました。

ただ、この方法は危ないところがいくつかあります。

1つ目はSubscribeはイベントを弱参照で保持していることです。
GCのタイミングで処理が消えることがあります。
それを抑制するには、イベントにはインスタンスのメソッドを渡すか、
インスタンスのメンバ変数を使用したラムダ式を渡すようにします。

2つ目はイベントの送受信はどのクラスからもできることです。
現在表示されているMVとVの間のみならず、既に破棄された画面のVMとも送受信してしまうかもしれません。
必要なくなったら、UnsubscribeやDisposeでイベントが呼ばれなくしましょう。

個人的意見ですが、そもそもVMからVを操作するようなこと自体がシステムを複雑化してしまうので、
設計レベルでそのようなことが可能な限り起きないようにしたほうが無難だと思います。

EventAggregatorでは処理を受信するスレッドを指定したり、自作のクラスを受け渡すこともできます。
ちなみに、最初は分かりやすくするために説明しませんでしたが、
PublishやSubscribeはPubSubEventの機能です。そのあたりも含め、全て自作できます。

最後に

EventAggregatorを使用すればVMからVも操作できますし、
Mから前のページのMを操作するといったこともできます。
自由度が高い分、扱いには注意しましょう。

13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?