shuhelohelo’s blog

Xamarin.Forms多めです.

MAUIでCommunityToolkit.Mvvmを使ったPubSubメッセージング

参考

www.youtube.com

メッセージングとは

送信側と受信側がお互いを意識しないで(依存しない)データのやり取りを行う仕組み、なのかな。

送信側は受信側のことを考えることなく送信したいときにメッセージを送信する。

受信側は送信側がどのタイミングでメッセージを送るかは気にせず待ち受けていて、送られてきたときに対応する。

こんな仕組み、と思う。

メリットは?

送信側、受信側がお互いに依存しないでデータのやり取りができること。

データの送受信そのものはもちろん大切だけれど、データの送受信を介して相手側の処理を開始するトリガにできること。

使い所は?

参考の動画のとおり、一覧ページから詳細ページに遷移した後、詳細ページで「削除」操作が行われたときに一覧ページで対象のアイテムが削除されるようにする、というようなページをまたいだ、任意のタイミングでの処理の実行に使う。

遷移のタイミングで、ということであれば遷移時にデータを受け渡すことができるけれど、メッセージングの場合は任意のタイミングでできるのがよい。

使い方

CommunityToolkit.Mvvm(8.0)をインストールしておく。 WeakReferenceMessengerクラスを使う。

メッセージの入れ物を作る

ここでいうメッセージとなるものはValueChangedMessage<T>型を継承したオブジェクトのこと。

このオブジェクトを受信側は待ち受け、送信側は送る。この型自体が送受信の識別子の役割も果たす。

例えばMyMessage:ValueChangedMessage<MyClass>というメッセージを用意したとする。

受信側は、「このMyMessage型のメッセージを待ち受けるよ!」というように書く。

送信側は、「MyMessage型のメッセージを送るよ!」というように書く。

なので、送受信したいメッセージの種類の数だけこういったValueChangedMessageを継承したクラスを用意する。

public class MyMessage : ValueChangedMessage<MyClass>
{
    public MyMessage(MyClass value) : base(value)
    {
    }
}

この場合、送りたいデータの型は"MyClass"型のデータ。 MyMessageの中にMyClass型のデータが含まれて送受信される。

受信側

受信側はWeakReferenceMessenger.Default.Register<T>()メソッドを使って、待ち受けるメッセージの種類と、それを受け取ったときの処理を書く。

以下のようにコンストラクタに書くことになると思う。

ラムダ式の中の第2引数(m)の中に送信側から送られてきたメッセージが入る。

この例は詳細ページ側で削除操作が行われたアイテムを一覧ページ側で一覧から削除するときの例。

    public MainPageViewModel()
    {
        //メッセージ受信側の登録
        //DeleteItemMessage型のメッセージが送られてきたときの処理を書く
        WeakReferenceMessenger.Default.Register<DeleteItemMessage>(this, (r, m) =>
        {
            //UIの更新を伴う場合はメインスレッドで実行されるようにする
            MainThread.BeginInvokeOnMainThread(() =>
            {
                Delete(m.Value);
            });
        });
    }

送信側

送信側は WeakReferenceMessenger.Default.Send()メソッドを使う。

例えば以下のようにMyClass型のデータをMyMessageに入れてメッセージを送る。

 var myClass = new MyClass();
 WeakReferenceMessenger.Default.Send(new MyMessage(myClass));

これは詳細ページで削除操作が行われたときに削除されたアイテムを載せてメッセージを送信する例。

    [RelayCommand]
    async Task Delete()
    {
        WeakReferenceMessenger.Default.Send(new DeleteItemMessage(TaskItem));
        await GoBack();
    }

おしまい

とても簡単にPubSubなメッセージングができた。

送受信それぞれのコードで相手を指定する記述は一切出て来ないことがわかる。

メッセージの型だけ知っていればよい。