Xamarin.FormsでMvvmHelpersを使ってみる
MVVMフレームワーク色々
MVVMパターンでのアプリケーション開発をサポートするライブラリやフレームワークは色々あります.
- Prism
- ReactiveProperty
- MvvmCross
- ReactiveUI
- MVVMLite
- MVVMHelpers
他にもあると思います.
それぞれ特徴があるので,合うものを探す必要があります.
今回はMvvmHelpers
について.Xamarin.Formsについてです.
MVVMフレームワークを使う理由
これらのフレームワークを使わなくてもMVVMパターンでアプリケーションを作成することはできます.
しかし,MVVMフレームワークを使うと,実装の手間を大きく減らすことができます.
難しいことはないのですが,各ViewModelで,その中の各プロパティで,こまごまとデータバインディングのための記述をする必要があるため,手間がかかります.
そういった手間をフレームワーク側に任せて,作りたいものに集中できるようにすることが,フレームワーク導入のメリットかと思います.
MvvmHelpersをインストールする
NugetパッケージマネージャからRefractored.MvvmHelpers
をインストールする.
BaseViewModelクラスを作成する
ViewModelは共通するプロパティやメソッドを実装することが多々あるので,そのようなプロパティ,メソッドをBaseViewModelとして定義しておき,各ViewModelクラスはそれを継承するようにすると,実装の手間を省くことができる.
共通化できるプロパティには以下のようなものがある.
- Title
- IsBusy
- IsNotBusy
- Iconのパス
BaseViewModelは例えば以下のようになる.
public class BaseViewModel : ObservableObject { private string _title; public string Title { get => _title; set => SetProperty(ref _title, value); } private string _subTitle; public string SubTitle { get => _subTitle; set => SetProperty(ref _subTitle, value); } private string _icon; public string Icon { get => _icon; set => SetProperty(ref _icon, value); } private bool _isBusy; public bool IsBusy { get => _isBusy; set { if (SetProperty(ref _isBusy, value)) IsNotBusy = !_isBusy; } } private bool _isNotBusy; public bool IsNotBusy { get => _isNotBusy; set => SetProperty(ref _isNotBusy, value); } private bool _canLoadMore; public bool CanLoadMore { get => _canLoadMore; set => SetProperty(ref _canLoadMore, value); } }
この内容であれば,MvvmHelpers.BaseViewModel
が用意されていて,それを継承するだけで良かったりする.
MvvmHelpersの機能を利用するためにはObservableObject
を継承すること.
ViewModelを作成する
このBaseViewModelを継承したクラスを作成します.
BaseViewModelに定義したいくつかのプロパティを使うだけのシンプルなViewModelとしてMainPageViewModel
を作成しました.
using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; namespace XFMvvmHelperPractice.ViewModels { public class MainPageViewModel : BaseViewModel { public MainPageViewModel() { //テスト this.Title = "Hello MvvmHelper"; this.SubTitle = "How to use MvvmHelper"; this.IsBusy = true; } } }
このMainPageViewModelを使うViewは以下のようにしました.
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="XFMvvmHelperPractice.Views.MainPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewmodels="clr-namespace:XFMvvmHelperPractice.ViewModels" mc:Ignorable="d"> <ContentPage.BindingContext> <viewmodels:MainPageViewModel /> </ContentPage.BindingContext> <StackLayout VerticalOptions="Center"> <Label FontSize="Large" HorizontalOptions="Center" Text="{Binding Title}" /> <Label FontSize="Medium" HorizontalOptions="Center" Text="{Binding SubTitle}" /> <ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" Color="Orange" /> </StackLayout> </ContentPage>
タイトル, サブタイトル, クルクル回るやつの3つのコントロールを持ち,それぞれがViewModelのTitle, SubTitle, IsBusyプロパティにバインディングされています.
このMainPageのBinding先のViewModelとしてMainPageViewModel
を指定しています.
<ContentPage.BindingContext> <viewmodels:MainPageViewModel /> </ContentPage.BindingContext>
これを実行した結果がこちらです.
ObservableCollectionをもっと使いやすく
アプリケーションの中でリストを表示させることがよくあります.
例えば,ToDoリストだったり,連絡先一覧だったりです.
このときリストに表示させるデータの型として使われるのがObservableCollection<T>
というクラスです.
List
表示するだけであればList
このObservableCollection
端末の処理性能次第ですが,多少は問題にならないとしても多くなればなるほど負荷が高くなりますし,なんだかスマートではありません.
ListAddRange
メソッドがあるのでまとめて追加などができるのですが,ObservableCollection
MvvmHelpersではこの問題を解決してくれます.
それがObservableRangeCollection<T>
です.
ObservableCollectionAddRange
メソッドを持っていることです.
以下のようにIEnumerable<T>
なコレクションを引数として受け取り,それを自身のコレクションに一括で追加します.
追加するコレクションにいくつアイテムがあろうとも,このAddRangeによって発生する変更通知は1回だけです.
ObservableRangeCollectionのCollectionChanged
イベントにイベントハンドラをセットして確認します.
People = new ObservableRangeCollection<Person>(); People.CollectionChanged += (s, e) => { //Peopleに変更(追加や削除. 各アイテムのデータの変更ではない)があった場合に出力 //確認用 Debug.WriteLine("People collection changed"); };
アプリケーションを実行して「GET PEOPLE」ボタンを押すとPeopleにデータが入れられますが,その際にVisual Studioの「出力(output)」ウィンドウに出力されるのは以下の1行だけです.1回しかイベントが発行されていないことがわかります.
とても便利です.
他にもRemoveRangeやReplaceRangeがあります.