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をバインドする