ViewModelからViewのメソッドを実行する。
音声ファイルを再生する。
http://d.hatena.ne.jp/trapemiya/20150330/1427700162
の続きです。遅くなりすみません。
さて、音声ファイルの再生方法は、android、iOS等、各プラットフォームによって異なります。よって、この音声を再生する記述は、各プラットフォーム毎のクラスに書いた方が、PCLで各プラットフォーム毎に場合分けして書くよりもスマートです。そうすると、PCL、つまりViewModelから各プラットフォームのクラスに対して、音声再生処理のお願いをしなければなりません。MVVMにおいてこの問題は良く出てくる話です。私も、WPFの開発をMVVMで始めた際にいろいろと悩みました。
ViewModelはViewのインスタンスとは疎結合ですから、ViewModelからViewに対して何らかの手動で連絡を取る必要があります。その手段として、ここではMessenger Pluginを使用します。プラグインはMvvmCrossに用意されている機能であり、IoCコンテナを利用して実現されています。
では、早速、Messenger Pluginを導入しましょう。
ソリューションエクスプローラーでPCLプロジェクトの「参照設定」を右クリックし、「NuGetパッケージの管理」をクリックします。そして、以下の図ように「Messenger Plugin」をインストールして下さい。
同様のことをandroid等、各プラットフォームのプロジェクトでも行って下さい。ここではandroid用プロジェクトのみを扱うものとします。
Messenger Pluginは、以下のようにMvx.ResolveメソッドでMvxMessengerHubオブジェクトを注入し、そのオブジェクトのPublishメソッドでメッセージを送ります。
var messenger = Mvx.Resolve<IMvxMessenger>(); messenger.Publish(new 汎用Message(this, "Play!"));
上記のメソッドが記述されているViewModel、および、メッセージオブジェクトである汎用Messageクラスの全容を以下に示します。
public class FirstViewModel : MvxViewModel { /// <summary> /// コンストラクタ /// </summary> public FirstViewModel() { PlayCommand = new MvxCommand(Play); } private string _hello = "Hello MvvmCross"; public string Hello { get { return _hello; } set { _hello = value; RaisePropertyChanged(() => Hello); } } public MvxCommand PlayCommand { get; private set; } private void Play() { var messenger = Mvx.Resolve<IMvxMessenger>(); messenger.Publish(new 汎用Message(this, "Play!")); } } public class 汎用Message : MvxMessage { public 汎用Message(object sender, object param) : base(sender) { this.Param = param; } public object Param { get; set; } }
メッセージを受け取る側、つまりViewでは以下のようにして、メッセージが来るのを待ちます。
var messenger = Mvx.Resolve<IMvxMessenger>(); MvxSubscriptionToken _tokenEnd = messenger.SubscribeOnMainThread<汎用Message>(OnReceiveMessage);
メッセージが来たらOnReceiveMessageメソッドが実行され、そこで音楽が再生されます。
上記のメソッドが記述されているViewのコードの全容を以下に示します。
public class FirstView : MvxActivity { protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.FirstView); //起動時に音楽を鳴らすのを止める。 //MediaPlayer.Create(this, Resource.Raw.c9).Start(); var messenger = Mvx.Resolve<IMvxMessenger>(); MvxSubscriptionToken _tokenEnd = messenger.SubscribeOnMainThread<汎用Message>(OnReceiveMessage); } public void OnReceiveMessage(汎用Message message) { if (message.Sender != ViewModel) return; MediaPlayer.Create(this, Resource.Raw.c9).Start(); } }
Messenger Pluginは、IoCコンテナの特徴の一つであるsingletonオブジェクトを介して、メッセージを伝達しています。Messenger Pluginがなぜsingletonになるかは、以下のソースコードの通り、Mvx.RegisterSingletonメソッドで登録されているからです。
MvvmCross/Plugins/Cirrious/Messenger/Cirrious.MvvmCross.Plugins.Messenger/PluginLoader.cs
https://github.com/MvvmCross/MvvmCross/blob/c306ba37afd9024f68b7a4f1fedcaf4cf7d01b8d/Plugins/Cirrious/Messenger/Cirrious.MvvmCross.Plugins.Messenger/PluginLoader.cs#L27
以上、おつかれさまでした。
(参考としたページ)
Executing UI Code from ViewModel on MVVMCross
http://stackoverflow.com/questions/15590776/executing-ui-code-from-viewmodel-on-mvvmcross