12
7

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-05-27

基本的なMVVMとデータバインディングのサンプルはこちら

概要

XamarinのページのPart 5. From Data Bindings to MVVMのInteractive MVVMの章のRGB版です。
前の章に関しては一番上のリンクからどうぞ
R,G,Bのスライダーを操作するとLabelの色が変わるサンプルを作ります。
インタラクティブ(相互作用)というタイトルの通り、バインドの方向を双方向にします。

ViewModel

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

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 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について訳してみた。

12
7
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
12
7