Xamarin.FormsでINotifyPropertyChangedの面倒な実装をReactivePropertyで解消する


## なにが面倒なのか

UI上のコントロールに表示する値を動的に変更する場合、ViewModel に INotifyPropertyChanged を実装するというのが[公式における定石](https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/)のようです（これをやらないとプロパティ値を変更してもUI上の表示が変わらない）。

たとえばこんな感じ。

```xml:XAML
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyApp"
    x:Class="MyApp.Views.MainPage">
    
	<Label Text="{Binding Greeting}" VerticalOptions="Center" HorizontalOptions="Center" />
    
</ContentPage>
```

```c#:コードビハインド
using Xamarin.Forms;

using MyApp.ViewModels;

namespace MyApp.Views
{
    public partial class MainPage : ContentPage
    {
        public MainPage() {
            InitializeComponent();
            this.BindingContext = new MainPageViewModel();
        }
    }
}
```

```c#:ViewModel
using System.ComponentModel;
using System.Threading.Tasks;

namespace MyApp.ViewModels
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        protected string _greetting;
        public string Greeting {
            get { return _greetting; }
            set {
                _greetting = value;
                OnPropertyChanged(nameof(Greeting));
            }
        }

        public MainPageViewModel() {
            this.Greeting = "Zzz...";
            SetPropertyValue();
        }

        private async void SetPropertyValue() {
            await Task.Run(() => {
                Task.Delay(3000).Wait();
                this.Greeting = "おはようございます";
            });
        }

		public event PropertyChangedEventHandler PropertyChanged;

		protected virtual void OnPropertyChanged(string propertyName) {
			if (PropertyChanged != null) {
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
    }
}
```

これで起動の3秒後に「おはようございます」がラベルに表示されるわけですが、今回はビューに配置するラベルが1個だけだから良いものの、数が多くなるとプロパティのアクセサを定義するのが超絶面倒です。

ワタシなどは2個目のアクセサを定義するのさえイヤになります。

ところがなんと ReactiveProperty というパッケージを利用すると、この面倒極まりない実装を省略できるそうです！

## パッケージ追加

NuGetで ReactiveProperty を探してきて追加します。
macOSだと追加に失敗するっぽいので、2.x系で。 → [関連記事](http://qiita.com/sudachi808/items/0af1f92b0545837e9ab2)

![nuget.png](https://qiita-image-store.s3.amazonaws.com/0/169798/29606cc0-a72b-6586-f873-c964b9c73ea2.png "nuget.png")


## 簡潔になったコード

```xml:XAML
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyApp"
    x:Class="MyApp.Views.MainPage">
    
	<Label Text="{Binding Greeting.Value}" VerticalOptions="Center" HorizontalOptions="Center" />
    
</ContentPage>
```

```c#:ViewModel
using System.Threading.Tasks;

using Reactive.Bindings;

namespace MyApp.ViewModels
{
    public class MainPageViewModel
    {
        public ReactiveProperty<string> Greeting { get; } = new ReactiveProperty<string>();

        public MainPageViewModel()
        {
            this.Greeting.Value = "Zzz...";
            SetPropertyValue();
        }

        private async void SetPropertyValue()
        {
            await Task.Run(() => {
                Task.Delay(3000).Wait();
                this.Greeting.Value = "おはようございます";
            });
        }
    }
}
```

これだけで前述のコードと同じ挙動になります。

ビューでバインドする時とプロパティの読み書き時に Value プロパティを介する必要がありますが、
INotifyPropertyChanged の実装とプロパティのアクセサ（自分で書くやつ）が不要になりました。素晴らしい！

プロパティ自体を Observable とすることで値の変更通知を PropertyChanged の代わりとするアイディアのようです。

とりあえずは以上です。


## こちらを参考にしました
ReactiveProperty オーバービュー
http://blog.okazuki.jp/entry/2014/05/07/014133 (パッケージ作者のブログ記事)

INotifyPropertyChanged実装のありえない面倒くささと、ReactivePropertyの信じられない素晴らしさ
http://qiita.com/ledsun/items/6f4ef754e5ae2507e531