前回はPrismのテンプレートでプロジェクトを作成して,AndrodとUWPで動作するところまでを確認しました。今回は,自動で作成されたソリューション内のプロジェクト構成や,フォルダー構成を確認していきます。
BlancApp1.AndroidとBlancApp1.UWP
自動で3つのプロジェクトが作成されていますが,その3つのうち,BlancApp1.AndroidとBlancApp1.UWPはそれぞれのデバイスで動作させるためのプロジェクトです。先ほどもやった通り,いずれかのデバイスのみで動作させる場合は,対象のプロジェクトを選択して,スタートアッププロジェクトに設定すれば,それぞれのデバイスで動作させることができます。
BlancApp1プロジェクト
BlancApp1プロジェクトには,すべてのデバイスに共通の処理を書いていくプロジェクトになります。よって,基本的に実装はこのプロジェクトにしていくことになります。AndrodやUWPなどのデバイス専用のプロジェクトには,各デバイスで固有の処理をさせるときや,画像ファイルを設置するとき以外はほとんど使用しません。
BlancApp1プロジェクトのフォルダー構成
PrismはMVVMの支援ツールなので,MVVMのアーキテクチャーで実装しやすいように構成されています。フォルダー構成は「Views」と「ViewModels」があり,画面はViewsフォルダーに〇〇Viewという名前でいれて,ロジック部分はViewModelsフォルダーに〇〇ViewModelという名前で作成していくことになります。
それ以外にはApp.xamlというファイルがあり,ここではViewとViewModelの紐づけ等が行われています。
MainPageViewModel.cs
MainPageViewModel.csの中身を見てみましょう。
using Prism.Commands; using Prism.Mvvm; using Prism.Navigation; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BlankApp1.ViewModels { public class MainPageViewModel : ViewModelBase { public MainPageViewModel(INavigationService navigationService) : base(navigationService) { Title = "Main Page"; } } }
ViewModelBaseが継承されており,コンストラクタにはINavigationServiceというものが指定されています。これは画面遷移をするときに必要なものですが,これをbaseに引き渡しているのがわかります。
コンストラクタの中では,Titleの設定も行われています。Titleプロパティはこのクラスには宣言されていませんが,これもViewModelBaseで宣言されている項目です。
ViewModelBase.cs
ViewModelBaseはBindableBaseというクラスを継承していますが,これはPrismでデータバインドをするためのクラスです。ViewModelBaseはさらにそれをラップして,画面遷移や,Titleなど,どの画面でも必要な項目を最初から実装しているクラスという事になります。よって,基本的には,ViewModelはすべてViewModelBaseを継承すればよいでしょう。
using Prism.Commands; using Prism.Mvvm; using Prism.Navigation; using System; using System.Collections.Generic; using System.Text; namespace BlankApp1.ViewModels { public class ViewModelBase : BindableBase, INavigationAware, IDestructible { protected INavigationService NavigationService { get; private set; } private string _title; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } public ViewModelBase(INavigationService navigationService) { NavigationService = navigationService; } public virtual void OnNavigatedFrom(INavigationParameters parameters) { } public virtual void OnNavigatedTo(INavigationParameters parameters) { } public virtual void OnNavigatingTo(INavigationParameters parameters) { } public virtual void Destroy() { } } }
データバインドとは?
データバインドとは,ViewにXamlで記述する画面コントロールのプロパティと,ViewModelに宣言するstring等のプロパティを同期させるための機能です。例えば画面のTitleとViewModelのTitleのどちらを変更しても,両方が連動して同時に変更されるような機能の事です。MVVMのアーキテクチャーパターンではViewに画面の要素を書き,ViewModelに画面の要素から切り離してロジックを書きます。だから画面でLabelを1つ使うとすれば,そのLabelのTextに対してViewModel側にLabelTextなどの名前でstringのプロパティを1つ作成します。ViewModelのLabelTextを変更すると実際の画面のLabelのTextも連動して変更すること,またはその逆で,画面のLabelのTextが変更されたら,ViewModel側のLabelTextも連動して変更される動作の事をデータバインディング(データバインド)と呼んでいます。
Titleのデータバインド
Prismはサンプルとして,デフォルトで作成されるファイルの中にデータバインディングするための記述をしてくれています。MainPage.xamlの5行目の「Title=”{Binding Title}”」の記述です。これは画面のTitleをViewModel側のTitleプロパティとデータバインディングさせるという意味になります。
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="BlankApp1.Views.MainPage" Title="{Binding Title}"> <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"> <Label Text="Welcome to Xamarin Forms and Prism!" /> </StackLayout> </ContentPage>
MainPageViewModel.csにTitleプロパティは宣言されていませんが,その基底クラスのViewModelBaseにTitleプロパティが宣言されています。このTitleプロパティと,画面のTitleが連動するようになっています。
namespace BlankApp1.ViewModels { public class MainPageViewModel : ViewModelBase { public MainPageViewModel(INavigationService navigationService) : base(navigationService) { Title = "Main Page"; } } }
Prismでデータバインディングさせるための記述はViewModelBaseのTitleの記述を見れば確認できます。Titleというstringのプロパティを作成する場合はprivateのstring変数「_title」を作成し,Titleプロパティのgetでreturnしています。Setは「SetProperty(ref _title, value);」という記述になっていますが,これは,値が変更されたときにView側に変更通知を発行するためのものです。また,値が変更されていないのにSetされたときには通知を起こさないための処置もされています。よってPrismでデータバインディングをするときは,この記述に習って記載していきます。
private string _title; public string Title { get { return _title; } set { SetProperty(ref _title, value); } }