眠いしお腹すいたし(´・ω・`)

C#関連を主に書きます。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

MVVMっぽくXamarin.Formsアプリ作ってみました。その2

前回

MVVMっぽくXamarin.Formsアプリ作ってみました。その1 - 眠いしお腹すいたし(´・ω・`)

の続きから

ViewModel

ViewModelですがINotifyPropertyChangedは実装しません。

ReactivePropertyを使用します。

github.com

XamarinFormsSampleStopWatch/StopwatchViewModel.cs at master · yuka1984/XamarinFormsSampleStopWatch · GitHub

コントローラの保持するモデルからReactiveProperty、ReactiveCollection、ObservableCollectionなどを作成します。

表示用のプロパティは基本的にReadOnlyReactivePropertyとしています。

入力用プロパティはReactivePropertyを使用します。

配列は基本的にReadOnlyReactivePropertyとしますが、必要であればObservableCollectionを作成します。

コマンドはReactiveCommandを使用します。

ReactiveCommandは他のReactivePropertyを元に実行可能状態を管理します。

ClearCommand = IsRuning.CombineLatest(elapsedtime, (run, t) => t > 0 && !run).ToReactiveCommand();
ClearCommand.Subscribe(x =>
            {
                IsRuning.Value = false;
                IsStart.Value = false;
                stopWatchController.Clear();
            });

コンストラクタでコントローラを受け取りReactivePropertyを作成していきます。

今回のサンプルではModelのプロパティは経過時間のmsecのlong値でしかないですが、それをRxで変形させてプロパティにしています。単純なlong値が時間フォーマット文字列に変形したり時計の針の角度に変形したりします。

Rotation = stopWatchController.StopWatchModel.ObserveProperty(x => x.ElapsedTime).Select(x => (double) (x/1000*6%360) - 90).ToReadOnlyReactiveProperty();

Time = stopWatchController.StopWatchModel.ObserveProperty(x => x.ElapsedTime).Select(x =>x.ToTimeFormat() + "->").ToReadOnlyReactiveProperty();

ロジックの結果であるModelは実体としてのデータであって表示のことは意識していないためコントローラの実装者はロジックの事に専念して実装を行うことができてUI担当者は実値を変形させることでUIを作成することができます。

ReactivePropertyを使用するとViewModelとロジック部をスッキリと分離することができとても良いです。当然Rxな書き方が可能となるためプロパティ同士の合成ができたり色々とつよいです。

ViewModelの再利用は考えていません。 ViewModelの再利用に関しては、過去いろいろ試したりしたけどうまくいったことがないので私の設計能力では無理だと思ってそれ以降考えたことはないです。

ViewModelの単体試験ですが、こちらも考えていません。 ただできないことはないかなぁと思ってます。 単体試験用のコントローラを注入してReactivePropertyのSubscriveにて値を記録するような形式でのテストが可能であると考えます。

ViewModelからのページ遷移

今回のサンプルではMessagingCenterを使用しています。

Publish and Subscribe with MessagingCenter - Xamarin

Appクラスのコンストラクタでページ遷移をSubscribeで実装しています。

XamarinFormsSampleStopWatch/App.cs at master · yuka1984/XamarinFormsSampleStopWatch · GitHub

ViewModelからSendしてページ遷移を呼び出します。

ToSaveCommand.Subscribe(
                x => MessagingCenter.Send(new NavigationMessage {IsModal = true}, NavigationMessage.ToSavePage));

正直、この実装はどうかな?って感じです。

もっと良い方法があれば知りたい感じです。

ページ間でのデータの受け渡しは必要に応じます。

今回のサンプルではロジック部の状態保持のみで実装可能であったためViewModel間での値の受け渡しは行っていませんが、例えばリストから詳細ページに移動するようなケースでは引数の受け渡しを行ったりします。

注意する点は画面遷移の為のデータ保持をコントローラで行ってはいけないということです。

今日はここまで。 ちょっとずつでごめんなさい。