Prism + ReactiveProperty入門

Post on 04-Aug-2015

1.254 views 13 download

Transcript of Prism + ReactiveProperty入門

Windows Phone開発のためのPrism + ReactiveProperty基本

2015/6/26 まんつーまん@調布

大田 一希

Prismとは

• Microsoft Patterns & Practicesチーム製のMVVMフレームワーク• 以下のプラットフォームをサポート

• WPF(超複雑)

• Silverlight(オワコン)

• Windows store app

• Windows Phone(今回の主題)

• Xamarin(Preview)

•最近MS P&PチームからMVP主体のチームに移管された

Prism.StoreAppsPrism.StoreAppsの中から電話向けに説明

Prism.StoreApps

• Universal app(Windows store app + Windows Phone app)版Prism

•以下の構成要素がある• Prism.Mvvm :MVVMをサポートする基本クラスを提供

• Prism.Mvvm.Phone :↑にPhone固有機能を提供

• Prism.StoreApps :Win store app + WP app固有機能を提供

• Prism.StoreApps.Phone:↑にWP固有機能を提供

覚えておきたいクラス

Prism.Mvvm

•本当にプレーンなMVVMの必要最低限の機能を提供するライブラリ

•以下の機能を提供• BindableBase class :INotifyPropertyChangedの基本実装

• DelegateCommand class :ICommandの基本実装

Prism.Mvvm.Phone

•以下の機能を提供• ViewModelLocator class :ViewとViewModelの紐づけ機能

Prism.StoreApps

• PrismのUniversal app版

•以下の機能を提供• VisualStateAwarePage class :ページの基本クラス

• ViewModel class :ViewModelの基本クラス

• SessionStateService class :中断時の一時データ保存用クラス

• FrameNavigationService class :画面遷移用クラス

Prism.StoreApps.Phone

• Prism.StoreAppsのPhone特化版

•以下の機能を提供• MvvmAppBase class :Appクラスの基本クラス

クラス詳解各クラスの使い方

BindableBase class

• MVVMには必須のINotifyPropertyChangedの実装クラス

• SetProperty<T>メソッドを使う

こんな感じにsetが書ける

コードスニペットに登録すると捗る

DelegateCommand class

• ReactiveProperty使うならいらない子なので割愛

ViewModelLocator class

•命名規約(カスタマイズ可能だけどやりかたは割愛)によりViewとViewModelを紐づける

•以下のような命名規約• AppNamespace.Views.HogePage(View名)

• AppNamespace.ViewModels.HogePageViewModel(View名+ViewModel)

この2つを結びつける

ViewModelLocator class

• ページの添付プロパティとして記述することで機能する

VisualStateAwarePage class

• Pageに便利機能を追加

• Prismを使う上でページはこいつを継承する必要がある

•以下の機能を提供• GoBackCommand property :戻る機能のCommand

• GoHomeCommand property :トップページへ戻る機能のCommand

• SaveState method :オーバーライドして中断時のデータ保存

• LoadState method :オーバーライドして中断時のデータ読込

• VisualStateの切り替え• DefaultLayout, PortraitLayout, MinimalLayoutを自動で切り替え(詳細は割愛)

VisualStateAwarePage class

•以下のように”空白のページ”テンプレートを書き換える• ViewModelLocatorも合わせて以下のようなXAMLがひな形

VisualStateAwarePageの名前

空間を定義

Pageタグを書き換え

VisualStateAwarePage class

•以下のように”空白のページ”のテンプレートを書き換える

OnNavigatedToメソッドのオー

バーライドを消す

基本クラスを

VisualStateAwarePageにする

ViewModel class

• BindableBaseを拡張して以下の機能を提供する• OnNavigatedToメソッド :画面遷移してきたときに呼ばれる

• OnNavigatedFromメソッド :画面から離れるときに呼ばれる

• 中断処理への対応 :RestorableState属性つけたプロパティの自動復元

ViewModel class

•基本以下のような書き方になる

SessionStateService class

•中断時のデータ保存用クラス

•実際に使うときはISessionStateService interface

•後述するMvvmAppBaseのプロパティとして定義される• Dictionary<string, object> SessionState { get; }プロパティがある

• ↑は、中断時のデータ保存場所

• RegisterKnownTypeメソッド• プリミティブ型以外をSessionStateに登録するときに型を登録するメソッド(しておかないと例外が飛ぶ)

FrameNavigationService class

•画面遷移をするためのクラス

•実際使うときはINavigationService interface

• MvvmAppBaseクラスのプロパティとして定義される

FrameNavigationService class

•画面遷移の仕方• ViewのXXXXPageに遷移するときは以下のように呼び出す

• NavigationService.Navigate(“XXXX”, null); // 第二引数は画面遷移パラメータ

• Frameにあるようなメソッドがある• GoBack() :戻る

• CanBoBack() :戻れる場合true

MvvmAppBase class

• Appクラスの基本クラス

• なが~いApp.xaml.csをシンプルに書ける

MvvmAppBase class

• Appクラスの定義方法

• App.xamlを以下のように書き換える

MvvmAppBaseの名前空間を

定義

Appタグを書き換え

MvvmAppBase class

• MainPageに遷移する場合のコードビハインド

長い処理を消して画面遷移す

るだけの処理へ

基本クラスをMvvmAppBaseへ

組み合わせて使う

Pageで画面遷移するには

• MvvmAppBaseのOnInitializeAsyncメソッドをオーバーライドする

• Pageに紐づくViewModelの生成をカスタマイズする• ViewModelにNavigationServiceを渡す

• MainPageViewModelの生成をカスタマイズする場合は以下のような感じ

Pageで画面遷移するには

• ViewModel側では以下のようにコンストラクタでINavigationServiceを受け取り、それを使って画面遷移をする

Modelはどうするの?

• Appクラスで作成してViewModelに渡すのがいいと思います

ReactiveProperty

ReactiveProperty

• Reactive Extensions(Rx)をベースにしたMVVMサポートライブラリ

• V ⇔ ViewModel⇔ Modelの間をRxでシームレスに繋ぐのが特徴

ReactiveProperty

•以下のクラスを提供• ReactiveProperty<T> class :ViewModelのプロパティ用

• ReactiveCommand class :ViewModelのCommand用

• ReadOnlyReactiveCollection<T> class:ViewModelのコレクション用

• その他拡張メソッドを提供• INotifyPropertyChangedの拡張メソッド

• ToReactivePropertyAsSynchronized method :MのプロパティとVMのReactivePropertyの同期をとるためのメソッド

• ObservableCollection<T>の拡張メソッド• ToReadOnlyReactiveCollection method :MのObservableCollection<T>と

VMのReadOnlyReactiveCollection<T>の同期をとるためのメソッド

ReactiveProperty class

• ViewModelに定義するプロパティ• public ReactiveProperty<string> Name { get; private set; }のように定義

• コンストラクタで初期化• this.Name = new ReactiveProperty<string>(); // nullを持った状態

• this.Name = new ReactiveProperty<string>(“なまえ”); // 初期値を持った状態

• this.Name = source.ToReactiveProperty(); // IObservable<T>から変換

• this.Name = person.ToReactivePropertyAsSynchronized(x => x.Name); // Modelのプロパティから変換

ReactiveProperty class

• IObservable<T>からの変換• 超便利なので覚えておくべき

• model // 何かINotifyPropertyChangedの実装クラス.PropertyChangedAsObservable(x => x.Name) // IObservable<T>に変換.ToReactiveProperty(); // ReactivePropertyに変換

• ↑でModelからViewModelへの一方通行値同期が可能

ReactiveProperty class

• ToReactivePropertyAsSynchronized methodも便利• model // INotifyPropertyChangedの実装クラス

.ToReactivePropertyAsSynchronized(x => x.Name); //Nameプロパティと同期

• model // INotifyPropertyChangedの実装クラス.ToReactivePropertyAsSynchronized(

x => x.Age, // Ageプロパティをx => x.ToString(), // M -> VMの時は文字列に変換してx => int.Parse(x)); // VM -> Mの時はintに変換する

ReactiveProperty class

• ToReactivePropertyAsSynchronized methodも便利• model // INotifyPropertyChangedの実装クラス

.ToReactivePropertyAsSynchronized(x => x.Age, // Ageプロパティをx => x.Age.ToString(), // M -> VMの時は文字列に変換してx => int.Parse(x), // VM -> Mの時はintに変換するignoreValidationErrorValue: true); // 変な値は通さない(次ページ参照)

ReactiveProperty class

•値の検証をサポート• // 何らかの方法でRPを作成

this.Hoge = xxxx.ToReactivePropertyAsSynchronized(…)// 検証ロジックを設定(nullの時はOKでそうじゃないときはエラーメッセージ).SetValidateNotifyError(x =>{

var x = 0;if (int.TryParse(x, out x)) { return null; }else { return "整数を入力してください"; }

});

ReactiveCommand class

• IObservable<bool>から生成可能なCommand• public ReactiveCommand HogeCommand { get; private set; }

• コンストラクタで以下のように初期化• this.HogeCommand = new ReactiveCommand(); // 常に実行可能なコマンド

• this.HogeCommand = source.ToReactiveCommand(); // IO<bool>がtrueの時だけ実行可能なコマンド

ReactiveCommand class

• コマンドの処理はSubscribeメソッドでやる• this.HogeCommand.Subscribe(_ =>

{// コマンド実行時の処理

});

ReadOnlyReactiveCollection class

• ModelのObservableCollection<T>をViewModelで読み取り専用コレクションとして公開する

•以下のように定義する• public ReadOnlyReactiveCollection<PersonViewModel> People { get;

private set; }

•以下のように初期化する• // modelでObservableCollection<Person>が定義されてるとする

this.People = model.People// model.Peopleと同期をとったPersonViewModelのコレクションを作成.ToReadOnlyReactiveCollection(x => new PersonViewModel(x));

組み合わせて使うPrismとReactiveProperty

基本はModelは普通に書く

• INotifyPropertyChangedとObservableCollection<T>による変更通知

•機能をメソッドとして提供

ViewModelをPrism + ReactivePropertyで

• ViewModel classを継承

• ReactiveProperty<T>でプロパティを定義

• OnNavigatedToメソッドでReactiveProperty<T>の初期化

• OnNavigatedFromメソッドで後始末

後始末

• ReactivePropertyとModelを接続したら最後に接続を切ること

• じゃないと予期せぬ処理が走ったりする

•具体的には• OnNavigatedToでCompositeDisposableに集める

• OnNavigatedFromでDisposeする

後始末

• こんな感じ• private CompositeDisposable disposable = new CompositeDisposable();

• OnNavigatedToで• this.Name = hoge.ToReactiveProperty().AddTo(this.disposable);

• this.People = model.People.ToReadOnlyReactiveCollection(x => new PersonViewModel(x)).AddTo(this.disposable);

• OnNavigatedFromで• this.disposable.Dispose();

まとめ

Prism

• BindableBase

• ViewModelLocator

• ViewModel

• MvvmAppBase(NavigationService, SessionStateService)• OnInitializeAsync

• OnLaunchApplicationAsync

ReactiveProperty

• ReactiveProperty<T>

• ReactiveCommand

• ReadOnlyReactiveCollection<T>

• INotifyPropertyChanged extension method• ToReactivePropertyAsSynchronized

• ObservableCollection<T> extension method• ToReadOnlyReactiveCollection

まとめ

• あとはケーススタディの積み重ね