昨日の ポスト を使ったのに、肝心の導入部分を説明するのを忘れていました。まあ Components から追加するだけなのですが。他のアドベントカレンダーとの掛け持ちで疲れたので、今日は軽く書いて済ませます。
Components で右クリック → Get more components → Reactive とかで検索 → 見つけたら Add to App で OK です。あ、この手順は .iOS でも .Android でも同じです。
イベントを Stream に変換する例を示してお茶を濁します。
まずこんな感じのどうでもいい画面を用意しまして、
UIButton.TouchUpInside
を IObservable
に変換する拡張メソッドを用意します。
//UIButtonExtensions.cs
public static class UIButtonExtensions
{
public static IObservable<string> ClickAsObservable(this UIButton button)
{
return Observable.FromEventPattern<EventArgs>(button, "TouchUpInside")
.Select(e => ((UIButton)e.Sender).TitleLabel.Text);
}
}
で、こんなコードを書きます。
//MainViewController_amb.cs
public override void ViewDidLoad()
{
base.ViewDidLoad();
Button1.ClickAsObservable()
.Publish(_ =>
Button2.ClickAsObservable()
.Amb(
Button3.ClickAsObservable()))
.Subscribe(btnName => InvokeOnMainThread(() =>
Label1.Text = btnName + " Clicked"));
}
Button1 を押すと処理の開始です。 Publish で分配して Amb は Button2 のクリックと Button3 のクリックで先に行われた方を Label1 に表示します。
Amb を Zip に変えてみます。
//MainViewController_zip.cs
Button1.ClickAsObservable()
.Publish(_ =>
Button2.ClickAsObservable()
.Zip(
Button3.ClickAsObservable(), (l,r) => new {l, r}))
.Subscribe(p => InvokeOnMainThread(() =>
Label1.Text = p.l + " and " + p.r + "Clicked"));
Zip は2つのシーケンスの結果を待ってから後続へ流します。 なので、Button2 と Button3 の両方が押されると、Label1 に表示されます。
どちらもフツーに書くとフラグ変数なんか使って実現すると思うんですけど、Rx を使うと読みやすいコードになると思います。
あと、私は Android-Java の開発では reactive4Java を使ってるんですが、あれには Observable.FromEventPattern
が無い(Java のイベントの Listener はイベントのマルチキャストに対応してないから仕方ない)ので、Xamarin にすることで「完全な」Rx を使うことができて、こりゃ勉強のしがいがあるなあと思ったのでした。
何の記事でしたっけ?という感じですけど Xamarin なら Linq も Rx も使えてハッピーという事で、今日は以上です。