前回までで,ViewとViewModelに分ける意味や,テストコードをどのように記述するのかという事を解説してきました。今回はViewとViewModelに分けたことで,実装しづらくなった部分の対処法を解説していきます。例えば画面遷移時のNavigation.PushAsync等はContentPageには問題なく記述できていましたが,ViewModelには記述できません。そこでViewModelにロジックを書く場合はどのようにして画面遷移をすればいいのか?やはりコードビハインド側にコードを書く必要があるのか?という問題が出てくるので,そのあたりの対処法を解説していきます。結果から言うと,画面遷移,メッセージ表示,デバイスごとの切り替えは,コードビハインドに書かなくても,ViewModel側に記述できるように,Prismは対応されています。今回はそのやり方を実装していきます。
画面遷移用の画面を作成
画面遷移用の画面を1つ追加します。
画面を作成するときは「Views」フォルダーに作成します。Viewsフォルダーを右クリックして,「追加」から「新しい項目」を選択します。
「新しい項目の追加」画面で左側のツリーから「Prism」を選択し,さらに「Xamarin.Forms」を選択します。中央に「Prism ContentPage(Xamarin.Forms)」が選択できるので,それを選択します。名前は「PageBView」にして「追加」ボタンを押下します。
Viewを作成すると自動的に対応する「ViewModel」も作成してくれます。
ただ,Viewを「PageBView」のように,語尾にViewを付けてしまうと,ViewModelは「PageBViewViewModel」というように,ViewViewModelという重複した名前になってしまいます。これをPageBViewModelになるようにファイル名やクラス名を変更します。
次のようにPageBViewModelに変更します。
App.xaml配下のApp.xaml.csにもPageBViewViewModelの記述があるのでPageBViewModelに変更します。
PageBView には,PageBViewであることがわかるようにPageBViewのXAMLに,ラベルを設置して,「Page b」とテキストに設定しておきます。
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms" prism:ViewModelLocator.AutowireViewModel="True" x:Class="BlankApp1.Views.PageBView" Title="{Binding Title}"> <Label Text="Page b"/> </ContentPage>
MainPageのXAMLにボタンを追加し,Textを「Next page」とし,CommandにはNextCommandをバインドしておきます。これで,NextCommandボタンをクリックしたら,PageBViewに遷移するように実装したいと思います。
<?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!" /> <Label Text="AAA" x:Name="LabelA"/> <Button Text="button a" Clicked="Button_Clicked"/> <Label Text="{Binding LabelC}"/> <Button Text="button c" Command="{Binding ButtonC}"/> <Button Text="Next page" Command="{Binding NextCommand}"/> </StackLayout> </ContentPage>
NextCommandのバインディングの方法は,前述のButtonCの時と同じやり方になります。
using BlankApp1.Conditions; using BlankApp1.Objects; using BlankApp1.Views; using Prism.Commands; using Prism.Mvvm; using Prism.Navigation; using Prism.Services; 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) { _pageDialogService = pageDialogService; ButtonC = new DelegateCommand(SetText); NextCommand = new DelegateCommand(PageBShow); Title = "Main Page"; LabelC = "DDD"; } private string _labelC = string.Empty; public string LabelC { get { return _labelC; } set { SetProperty(ref _labelC, value); } } public DelegateCommand ButtonC { get; set; } public DelegateCommand NextCommand { get; set; } private void SetText() { LabelC = "EEE"; } private void PageBShow() { NavigationService.NavigateAsync("PageBView"); } } }
NextCommandという名前でDelegateCommandのプロパティを作成し,コンストラクタでインスタンスを生成します。引数のActionにはPageBShowというメソッド名を指定します。PageBShowメソッドは画面遷移のためのコードを書く必要がありますが,ここでNavigationServiceというものを使っています。これはMainPageViewModelのコンストラクタで取得し,baseに引き渡しているものです。NavigationServiceを使用することで,ViewModel側でも簡単に画面遷移ができるようになっています。画面遷移をするにはNavigationServiceに続けてNavigateAsyncを記述し,引数に遷移したいViewの名前を記載します。今回は「PageBView」と記載したため,これでPageBViewに画面遷移できるようになりました。これで一度実行してみましょう。 画面が起動しました。
「NEXT PAGE」ボタンを押下するとPageBViewが表示されれば成功です。
「Page b」が表示されました。
これで画面遷移がうまくできていることが確認できました。