Xamarin.Forms MessagingCenterの利用
身内向け
下記、サンプルソースを元に記述します。
MVVMのViewとViewModelやModelの結合度を低くするために利用するもののようです。変に相互参照が増えすぎるのも汚いのでそういうものだと思っています。
MainPage.xaml.cs
public MainPage() { InitializeComponent(); //ここでViewはViewModelを参照します BindingContext = new MainPageViewModel(); }
上のようにViewはViewModelを参照しています。
MainPageViewModel.cs
public ICommand DependencyServiceCommand => new Command(() => { var openUriService = DependencyService.Get<IOpenUriService>(); openUriService.OpenUri(URIText); });
ボタンを押したときはViewModelがイベントをキャッチしています。
そして、画面遷移やダイアログを出せるのはContentPageを継承しているViewです。
ということで、「ボタンを押したときに画面遷移やダイアログを出すときどうするのか?」という点を解決するためにViewModelからViewへ通知を行う必要が出てきます。
そこで利用するのはMessagingCenterとなります。
画面遷移
MainPage.xaml.cs
protected override void OnAppearing() { base.OnAppearing(); //イベントのセット MessagingCenter.Subscribe<MainPageViewModel>(this, "MovePage1", async (_) => { await Navigation.PushModalAsync(new Page1(), true); }); }
画面起動時のOnAppearingの時にMessagingCenter.Subscribeでイベントをセットします。ジェネリックに与えるのは送信元のクラスとなります。
MainPageViewModel.cs
public ICommand MovePage1 => new Command(() => MessagingCenter.Send(this,"MovePage1"));
そして、ボタンを押されたときにメッセージを送信します。
メッセージ送信時にパラメータも渡す
パラメータの受け渡しもできます。
Page1.xaml.cs
//タプルにして複数の個の値を渡す MessagingCenter.Subscribe<Page1ViewModel, (string, string)>(this, "ShowMessage", (_, t) => { //メッセージダイアログ DisplayAlert(t.Item1, t.Item2, "OK"); });
少しかみ砕きます。<Page1ViewModel, (string, string)> と (, t) の関係ですが、Page1ViewModelがで (string, string)がtとしています。(string, string)の一つ目がt.Item1で二つ目がt.Item2です。
Page1ViewModel.cs
public ICommand MessageCommand => new Command(() => MessagingCenter.Send(this, "ShowMessage", ("Message", MessageText ?? "Empty.")));
これはテキストボックスに入力されたテキストをダイアログに出すサンプルです。(string,string)を必要に応じて変えてください。
MessagingCenter.Subscribeについて
MessagingCenter.Subscribeはイベントハンドラの+=と同じです。
試しに下記のように書き換えてみてください。同じものを二回実行するようにしてみます。
Page1.xaml.cs
//タプルにして複数の個の値を渡す MessagingCenter.Subscribe<Page1ViewModel, (string, string)>(this, "ShowMessage", (_, t) => { //メッセージダイアログ DisplayAlert(t.Item1, t.Item2, "OK"); }); MessagingCenter.Subscribe<Page1ViewModel, (string, string)>(this, "ShowMessage", (_, t) => { //メッセージダイアログ DisplayAlert(t.Item1, t.Item2, "OK"); });
これで実行するとダイアログが2回表示されるはずです。適切にイベントを破棄(MessagingCenter.Unsubscribe)しないとバグのもととなります。