随分昔に書いてますね。
最近は事情も変わったので改めて書いてみようと思います。
ReactivePropertyは?
Reactive ExtensionsをベースにしたMVVMの支援ライブラリです。
Xamarinでも使えるの?
Xamarin.AndroidとXamarin.iOSとXamarin.Formsに対応しています!ここでは、Xamarin.Androidでの使い方を紹介したいと思います(Mac持ってない)。因みに、ここで紹介するのと同じ感覚でiOSアプリでも使えるので興味を持った人は試してみてください!
Hello world的なもの
新規作成したときに作成されるカウントアップアプリをReactivePropertyを使って再現したみたいと思います。
プロジェクトの作成
Blank App(Android)を作成します。そして、NuGetからReactivePropertyを参照に追加します。
Counterクラスの作成
カウンターのクラスを作ります。普通のC#のクラスです。
using System.ComponentModel; namespace CounterApp { public class Counter : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private int value; public int Value { get { return this.value; } private set { this.value = value; this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Value))); } } public void Increment() { this.Value++; } } }
ViewModelの作成
次にMainActivityのViewModelになるMainActivityViewModelクラスを作成します。
using Reactive.Bindings; using Reactive.Bindings.Extensions; using System; using System.Linq; using System.Reactive.Linq; namespace CounterApp { public class MainActivityViewModel { // Model private Counter Model { get; } = new Counter(); // Viewへ公開するインターフェース public ReadOnlyReactiveProperty<string> CounterValue { get; } public ReactiveCommand IncremantCommand { get; } public MainActivityViewModel() { // Counter.Valueを監視して文字列化 this.CounterValue = this.Model .ObserveProperty(x => x.Value) .Select(x => x.ToString()) .ToReadOnlyReactiveProperty(); // インクリメントするコマンド this.IncremantCommand = new ReactiveCommand(); this.IncremantCommand.Subscribe(_ => this.Model.Increment()); } } }
ここまでは、普通のC#とReactivePropertyを使ったプログラミングです。
Vの作成
次にMainActivityに行きます。ReactivePropertyではAndroidのViewとバインドするための拡張メソッドとしてSetBindingというメソッドを提供しています。これを使うとコントロールのプロパティとReactivePropertyをバインドすることが出来ます。
また、コントロールのイベントをIObservableに変換したあとSetCommand拡張メソッドでコマンドを設定することで、コントロールのイベントとCommandを紐づけることが出来ます。
コードを書いてみましょう。
using Android.App; using Android.OS; using Android.Widget; using Reactive.Bindings; using System.Reactive.Linq; namespace CounterApp { [Activity(Label = "CounterApp", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { private MainActivityViewModel ViewModel { get; } = new MainActivityViewModel(); protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); // Get our button from the layout resource, // and attach an event to it var button = FindViewById<Button>(Resource.Id.MyButton); // ButtonのTextとバインド button.SetBinding( x => x.Text, this.ViewModel.CounterValue); // ButtonのClickイベントとバインド Observable.FromEventPattern(button, nameof(Button.Click)) .SetCommand(this.ViewModel.IncremantCommand); } } }
axmlに書いてバインドはできないのでごめんなさい。でもコードでも割と直感的に書けるかなと思ってます。
実行すると
以下のようになります。
気になった人は
因みに公式でしっかり書いてるのはこちら。 コレクションのバインドもサポートしています。
Xamarin.Formsで使ってくれてる人もいる
ちゃんとXamarin.Formsでも使えるよっていうことで!