45
41

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Xamarin.Forms と ReactiveProperty で快適MVVM生活

Last updated at Posted at 2014-09-09

 Xamarin.Forms は、Xamarin に新たに搭載されたクロスプラットフォームUIフレームワーク&MVVMフレームワークです。
 ReactiveProperty は、MVVMの(特に ViewModelの)実装を強力にサポートしてくれる、Reactive Extensions を基盤としたライブラリです。

両者を組み合わせると、Android/iOSアプリが COOL な感じで書けるんじゃないか、という事で試してみました。

0. 環境など

Mac + Xamarin Studio を使いますが、Windows + Visual Studio + Xamarin-Addin でもイケると思います。

1. 導入

プロジェクトの作成

新規ソリューションを、[C#]−[Mobile Apps]−[Blank App(Xamarin.Forms Portable)]で作成します。

PCL の Profile を変更

 作成されたソリューションの一番上にあるプロジェクト(.Android とか .iOS が付いていないやつ)のプロジェクト設定を開いて Profile を PCL 4.5 - Profile49 に変更します。元々の Profile78 では ReactiveProperty が Nuget からインストールできないためです。最近のプラットフォームを対象にするなら、あまり影響はなさそうです。

Nuget で Reactive Extensions と ReactiveProperty を追加

 メニューの[プロジェクト]ー[Add Packages]で Nuget のダイアログを開き、図のように 「Reactive Extensions - Main Library」と「ReactiveProperty Portable」を追加します。

(Reactive Extensions の追加の際、なにやらWarningが出るようですが、とりあえず進めます。)

2. ViewModel の実装

 PCL のプロジェクトに、FirstViewModel.cs を作成します。
 FirstViewModel は、以下のようなプロパティとコマンドを持ちます。

  • InputTextプロパティ : EditBox の入力に応じて更新
  • DisplayTextプロパティ : InputText の変化から1秒後に、InputText を大文字にして更新
  • Clearコマンド : InputText が 'clear' の時のみ有効。実行すると InputText を空にする。

これらの実装が下のようになります。

FirstViewModel.cs
using System;
using Codeplex.Reactive;
using System.Reactive.Linq;

namespace FormsWithRxProperty.ViewModels
{
    public class FirstViewModel
    {
        private readonly ReactiveProperty<string> _inputText = 
            new ReactiveProperty<string>("Hoge");
        public ReactiveProperty<string> InputText 
        { 
            get { return _inputText; }
        }

        public ReactiveProperty<string> DisplayText
        {
            get; private set;
        }

        public ReactiveCommand Clear
        {
            get; private set;
        }

        public FirstViewModel()
        {
            // DisplayText は、InputText の変更から1秒後に大文字にして更新
            this.DisplayText = _inputText
                .Delay(TimeSpan.FromSeconds(1))
                .Select(x => x.ToUpper())
                .ToReactiveProperty();

            // InputText が `clear` の時に実行可能
            this.Clear = _inputText
                .Select(x => x.Equals("clear"))
                .ToReactiveCommand();
            // 実行されたら、InputText を空にする
            this.Clear.Subscribe(_ => _inputText.Value = String.Empty);
        }
        
    }
}

 面倒な INotifyPropertyChanged の実装が必要なく、すっきりと記述できます。
 また、他のプロパティに関連して(反応して)値が変化するプロパティや、コマンドの利用可否などが、Reactive Extensions の機能により、流れるように記述できます。

3. 画面及び ViewModel との Binding の実装

 画面(UI)は、Xamarin.Forms の恩恵で、Android/iOS 共通で実装できます。XAML も使えますが、よく知らないのでコードでUIを記述します。

 PCL のプロジェクトに、 FirstPage.cs を作成し、以下のように実装します。

FirstPage.cs
using System;
using Xamarin.Forms;
using FormsWithRxProperty.ViewModels;

namespace FormsWithRxProperty.Pages
{
    public class FirstPage : ContentPage
    {
        public FirstPage()
        {
            // UI
            var entry = new Entry
            {
                Text = "Hello, Forms!",
                VerticalOptions = LayoutOptions.Center,
                HorizontalOptions = LayoutOptions.FillAndExpand,
            };

            var label = new Label
            {
                VerticalOptions = LayoutOptions.Center,
                HorizontalOptions = LayoutOptions.CenterAndExpand,
            };

            var button = new Button
            {
                Text = "Clear (type 'clear' to enable)",
                VerticalOptions = LayoutOptions.Center,
                HorizontalOptions = LayoutOptions.FillAndExpand,
            };

            this.Content = new StackLayout
            {
                Padding = new Thickness(50f),
                VerticalOptions = LayoutOptions.Start,
                HorizontalOptions = LayoutOptions.Fill,
                Orientation = StackOrientation.Vertical,
                Children =
                {
                    entry,
                    label,
                    button
                }
            };

            // ViewModel との Binding
            this.BindingContext = new FirstViewModel();
            entry.SetBinding<FirstViewModel>(Entry.TextProperty, vm=>vm.InputText.Value);
            label.SetBinding<FirstViewModel>(Label.TextProperty, vm=>vm.DisplayText.Value);
            button.SetBinding<FirstViewModel>(Button.CommandProperty, vm=>vm.Clear);
        }
    }
}

 ちょっと長いですが、画面に「エディットボックス」「ラベル」「ボタン」が縦に並んでいるだけです。

 下部の4行で、FirstViewModel の各プロパティ、コマンドと Bind しています。

 もともとあった App.cs は、FirstPage を生成するだけにします。

App.cs
using System;
using Xamarin.Forms;
using FormsWithRxProperty.Pages;

namespace FormsWithRxProperty
{
    public class App
    {
        public static Page GetMainPage()
        {	
            return new FirstPage();
        }
    }
}

動かす!

.Android か .iOS の付いたプロジェクトをスタートアップにして、実行します。

追記 2014.9.10

実機で動作確認するの忘れてました(実機はAOTなのに対してiOSシミュレータはJITなのでリフレクションとかが普通に動いてしまう)。
実機でも問題なく動作しました!

追記 2014.9.11 INotifyPropertyChanged の利用

ViewModel は INotifyPropertyChanged を実装して作成するのが一般的です。既にそのようにして作られた ViewModel でも IObservable 化して、ReactiveProperty で利用できます。

SecondViewModel.cs
public class SecondViewModel : INotifyPropertyChanged
{
    public ReactiveProperty<string> ValidationAttr { get; private set; }
    public event PropertyChangedEventHandler PropertyChanged;

    private string _myName = "HoGe";
    public string MyName 
    {
        get { return _myName; }
        set 
        { 
            if (_myName == value) return;

            _myName = value;
            PropertyChanged(this, new PropertyChangedEventArgs("MyName"));
        }
    }

    public ReactiveProperty<string> LowerText { get; private set; }

    private ICommand _resetCommand;
    public ICommand ResetCommand
    {
        get
        {
            return _resetCommand ?? (_resetCommand = 
                new Xamarin.Forms.Command(() => MyName = "XAAAAMAAARIN!!"));
        }
    }

    public SecondViewModel()
    {
        this.LowerText = this.ObserveProperty(x => x.MyName)
            .Select(x => x.ToLower())
            .ToReactiveProperty();
    }
}

まとめ

 Reactive Extensions のメリットを活かして MVVM を構築できる ReactiveProperty と、ワンソースで Android/iOS の画面を定義でき、さらに Binding までも共通にできる Xamarin.Forms の組み合わせは、今後のモバイルアプリケーション開発をとても効率的にしてくれます、 そしてなにより楽しい!

 今回のサンプルプログラムは

 に置きましたので、是非試してみてください。

ReactiveProperty

Xamarin.Forms

45
41
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
41

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?