Xamarin に Reactive Extensions を導入する

昨日の ポスト を使ったのに、肝心の導入部分を説明するのを忘れていました。まあ Components から追加するだけなのですが。他のアドベントカレンダーとの掛け持ちで疲れたので、今日は軽く書いて済ませます。

Reactive Extensions を導入する

Components で右クリック → Get more components → Reactive とかで検索 → 見つけたら Add to App で OK です。あ、この手順は .iOS でも .Android でも同じです。

使ってみましょうか

イベントを Stream に変換する例を示してお茶を濁します。

まずこんな感じのどうでもいい画面を用意しまして、

install rx to xamarin ios 02

UIButton.TouchUpInsideIObservable に変換する拡張メソッドを用意します。

//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"));
}

Observable.Amb (先にきた値を流す)

Button1 を押すと処理の開始です。 Publish で分配して Amb は Button2 のクリックと Button3 のクリックで先に行われた方を Label1 に表示します。

Observable.Zip (どちらの値も待つ)

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 も使えてハッピーという事で、今日は以上です。