LoginSignup
13

More than 5 years have passed since last update.

Xamarin.Formsで基本的なデータバインディング

Last updated at Posted at 2016-05-26

Qiita初投稿です。間違いやスペルミスがありましたらご指摘ください。

概要

XamarinのページのPart 5. From Data Bindings to MVVM のシンプルなViewModelについて実際にやってみようと思います。
内容は現在の時刻をLabelで表示し、毎秒更新するという内容です。

変更点

原文ではプロパティがDateTimeとなっていましたが、クラス名と紛らわしかったのでMyDateTimeという名前にしてあります。

ViewModelを作る

まずはViewModelの基礎を作ります。

using System;
using System.ComponentModel;
using Xamarin.Forms;

namespace XamarinSample2
{
    class ClockViewModel
    {
        DateTime myDateTime;

        public ClockViewModel()
        {
            this.MyDateTime = DateTime.Now;
            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {

                MyDateTime = DateTime.Now;
                return true;
            });
        }

        public DateTime MyDateTime
        {
            set
            {
                if (myDateTime != value)
                {
                    myDateTime = value;
                }
            }
            get { return myDateTime; }
        }

    }
}

クラスを見ていきます
DateTime型のプロパティMyDateTimeを持ち、コンストラクタで現在時刻に設定しています。
セッターで、代入された値が同じ時は更新しない理由は、ここに後述するイベント処理を挟むからです。
そしてコンストラクタで毎秒ごとにMyDateTimeを更新するようなタイマーを設定しています。

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>

    <Label x:Name="label"
           Text="{Binding MyDateTime, StringFormat='{0:T}'}"
           FontSize="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand">
      <Label.BindingContext>
        <local:ClockViewModel />
      </Label.BindingContext>
    </Label>

   </StackLayout>
</ContentPage>

まず注意したいのはContentPageの属性にXML名前空間:xmlns:localとして先ほどのViewModelがある名前空間を宣言していることです。
そしてLabelのLabel.BindingContextで、localのClockViewModelクラスを指定しています。
これでプロパティにバインドできるので、LabelのTextをMyDateTimeとバインドします。

実行すると実行時の時間は表示されますが、更新はされないと思います。
これはViewModelにINotifyPropertyChangedが実装されていないためです。
では実際に実装してみましょう

ViewModelにINotifyPropertyChangedを実装する

ClockViewModelにINotifyPropertyChangedを実装してみます。

namespace XamarinSample2
{
    class ClockViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        DateTime myDateTime;

        public ClockViewModel()
        {
            this.MyDateTime = DateTime.Now;
            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {

                MyDateTime = DateTime.Now;
                return true;
            });
        }

        public DateTime MyDateTime
        {
            set
            {
                if (myDateTime != value)
                {
                    myDateTime = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("MyDateTime"));
                }
            }
            get { return myDateTime; }
        }

    }
}

DateTimeのセッターに注目してください。MyDateTimeが変わった時、INotifyPropertyChangedを実装して作ったPropertyChangedイベントを発火させています。これによりViewが変化するはずです。
PropertyChangedの2番めの引数にPropertyChangedEventArgsを渡していますが、このときプロパティ名を間違えないよう気をつけてください。

これで実行すると、毎秒更新される時計が出来るはずです。

まとめ

  • ViewModelにINotifyPropertyChangedを実装し、PropertyChangedイベントを発火させる
  • Viewで名前空間を宣言し、BindingContextでViewModelをバインドする

参考記事

Xamarinのxamlのデータバインディングのpart4について訳してみた。

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
13