Xamarin.FormsでインタラクティブなMVVM サンプル

基本的なMVVMとデータバインディングのサンプルは[こちら](http://qiita.com/Tachibana446/items/302fbf2a321828a7cfba)

# 概要
Xamarinのページの[Part 5. From Data Bindings to MVVM](https://developer.xamarin.com/guides/xamarin-forms/user-interface/xaml-basics/data_bindings_to_mvvm/)のInteractive MVVMの章のRGB版です。
前の章に関しては一番上のリンクからどうぞ
R,G,Bのスライダーを操作するとLabelの色が変わるサンプルを作ります。
インタラクティブ（相互作用）というタイトルの通り、バインドの方向を双方向にします。

# ViewModel
Viewモデルには、ラベルの色Colorインスタンスのプロパティと、double型のRed,Green,Blueプロパティを持つことにします。
プロパティの変更をViewに伝えるためにINotifyPropertyChangedインターフェイスを実装します。

~~~ C#
namespace XamarinSample2
{
    class RGBViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        double red, green, blue;
        Color color;

        public double Red
        {
            set
            {
                if (red != value)
                {
                    red = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Red"));
                    SetNewColor();
                }
            }
            get { return red; }
        }

        public double Green
        {
            set
            {
                if (green != value)
                {
                    green = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Green"));
                    SetNewColor();
                }
            }
            get { return green; }
        }
        public double Blue
        {
            set
            {
                if (blue != value)
                {
                    blue = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Blue"));
                    SetNewColor();
                }
            }
            get { return blue; }
        }

        public Color Color
        {
            set
            {
                if (color != value)
                {
                    color = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Color"));
                    Red = value.R;
                    Green = value.G;
                    Blue = value.B;
                }
            }
            get { return color; }
        }

        public RGBViewModel()
        {
            this.Color = Color.White;
        }

        private void SetNewColor()
        {
            this.Color = Color.FromRgb(Red, Green, Blue);
        }
    }
}

~~~

R,G,Bのプロパティが変更されると、Colorを変更するSetNewColorを呼び出し、PropertyChangedイベントを発火させます。
逆にColorプロパティが変更された時も、R,G,Bを変更してPropertyChangedを発火します。

この時、Setアクセサでvalueが現在値と変わらない時は更新しないif文があることに注意してください。
これがないと、Redが変更される→Colorが変更される→Redを更新する→Colorが変更される……という無限ループになってしまいます。

# View

~~~ XML
<?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:XamarinSample2;assembly=XamarinSample2"
             x:Class="XamarinSample2.View.StartPage">

  <StackLayout>
    <StackLayout.BindingContext>
      <local:RGBViewModel />
    </StackLayout.BindingContext>
    <Label x:Name="label"
           Text="TEXT TEXT"
           TextColor="{Binding Color}"
           FontSize="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand">
    </Label>
    <!-- RGB Slider -->
    <Slider Value="{Binding Red,Mode=TwoWay}" />
    <Slider Value="{Binding Green,Mode=TwoWay}" />
    <Slider Value="{Binding Blue,Mode=TwoWay}" />

    <!-- RGB Label -->
    <StackLayout Orientation="Horizontal">
      <Label Text="{Binding Red,StringFormat='{0:F2}'}"/>
      <Label Text="{Binding Green,StringFormat='{0:F2}'}" />
      <Label Text="{Binding Blue,StringFormat='{0:F2}'}" />
    </StackLayout>
  </StackLayout>
</ContentPage>
~~~

ContentPageの属性で、XML名前空間：localとして先ほどのViewModelのあるnamespaceを宣言しています。
そして、StackLayoutのBindingContextに先ほどのViewModelを設定しています。
BindingContextは、子要素にも適用されるので、StackLayoutの子要素でもバインドすることが出来ます。
LabelのTextColor属性をViewModelのColorプロパティとバインディングしているので、Labelのカラーが変わります。

スライダーに注目してください。Mode=TwoWayという文が書かれています。これはバインディングの方向を表していて、これによってスライダーの値とViewModelの色のプロパティを相互にバインドしています。
これがないとスライダーを動かしてもViewModelが変更されません。

一方その下に現在のR,G,Bを表すLabelがありますが、こちらはLabelの内容をViewModelに通知する必要が無いので、Modeを指定していません。

Modeには以下の様な種類があるようです（まだOneWayとTwoWayしか使ったことがない…）

|Mode|方向|
|----|:----:|
|OneWay|ViewModel→View|
|TwoWay|ViewModel↔View|
|OneWayToSource|ViewModel←View|
|OneTime|最初の一度だけViewModelからViewへ|

# まとめ
- BindingのModeをTwoWayに指定することで、相互作用するMVVMができる
- ViewModelのプロパティのSetアクセサは値が変更された時だけPropertyChangedイベントを発火する

# 参考記事
[Xamarinのxamlのデータバインディングのpart4について訳してみた。](https://junk-code.blogspot.jp/2016/04/xamarinxamlpart4.html)