最終更新:2019年3月19日
Xamarin.Formsでページ間で値を受け渡しするいい方法がないかと色々考えてみました。今回は次のような簡単な状況を想定します。
最初のページ(MainPage)でEntryに値を入力する
↓
次のページ(SecondPage)で、最初のページのEntryに入力した値をLabelに表示する
考えた方法は以下の3通りです。MainPageからSecondPageのどこに値を渡すかで場合分けしています。
1.コンストラクタに値を渡す
2.プロパティに値を渡す
3.メソッドに値を渡す
4.遷移先のページのBindingContextに渡す(2019/3/19 追記)
なお、1~3の画面は共通なので先に掲載します。
MainPage.xaml(値を渡すページ)
<?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:XF_NavigationPage" x:Class="XF_NavigationPage.MainPage"> <StackLayout VerticalOptions="Center"> <Entry x:Name="entry" HorizontalOptions="FillAndExpand" /> <Button x:Name="button" Text="To Second Page" HorizontalOptions="Center" Clicked="Handle_Clicked" /> </StackLayout> </ContentPage>
SecondPage.xaml(値を受け取るページ)
<?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="XF_NavigationPage.SecondPage"> <ContentPage.Content> <StackLayout VerticalOptions="Center"> <Label Text="前のページから受け取った値" HorizontalOptions="Center"/> <Label x:Name="label" HorizontalOptions="Center"/> </StackLayout> </ContentPage.Content> </ContentPage>
1.コンストラクタに値を渡す
コードビハインドに以下のように記述します。
MainPage.xaml.cs
using System; using Xamarin.Forms; namespace XF_NavigationPage { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } void Handle_Clicked(object sender, EventArgs e) { var name = entry.Text; Navigation.PushAsync(new SecondPage(name)); } } }
SecondPage.xaml.cs
using Xamarin.Forms; namespace XF_NavigationPage { public partial class SecondPage : ContentPage { public SecondPage(string name) { InitializeComponent(); label.Text = name; } } }
NavigationPageでSecondPageのインスタンスを作る時にコンストラクタに値を渡しています。
それでは動きを見てみましょう。
うまくいっていますね!・・がこの方法では困ることがあります。SecondPageのXAMLのプレビューがエラーになるのです。
これでは画面を作る時に不便なので、この方法はやめたほうが良さそうです。
2.プロパティに値を渡す
それならSecondPageにプロパティを定義して、インスタンスを作る時にプロパティに値を渡せば良いのでは?と考えました。
MainPage.xaml.cs
using System; using Xamarin.Forms; namespace XF_NavigationPage { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } void Handle_Clicked(object sender, EventArgs e) { var name = entry.Text; //SecondPageクラスのNameプロパティに値を渡す Navigation.PushAsync(new SecondPage {Name=name}); } } }
SecondPage.xaml.cs
using Xamarin.Forms; namespace XF_NavigationPage { public partial class SecondPage : ContentPage { //コンストラクタ public SecondPage() { InitializeComponent(); } //画面が表示される時に実行 protected override void OnAppearing() { NameSet(Name); } //プロパティを追加 public string Name { get; set; } //ラベルのテキストを設定するメソッドを追加 public void NameSet(string name) { label.Text = name; } } }
最初はOnAppearingなしで、コンストラクタにNameSetメソッドを入れていましたが、それでは値を受け取れませんでした。この対策のためOnAppearingを使っています。
それでは動きを確認してみましょう。
一応、値は受け渡しできていますが、SecondPageで受け取った値が遅れて表示されるのでちょっと微妙ですね。
3.メソッドに値を渡す
それならメソッドに直接値を渡してしまえばいいのでは?と思ってコードを以下のようにしてみました。
MainPage.xaml.cs
using System; using Xamarin.Forms; namespace XF_NavigationPage { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } void Handle_Clicked(object sender, EventArgs e) { var name = entry.Text; var secondPage = new SecondPage(); Navigation.PushAsync(secondPage); secondPage.NameSet(name); } } }
SecondPage.xaml.cs
using Xamarin.Forms; namespace XF_NavigationPage { public partial class SecondPage : ContentPage { public SecondPage() { InitializeComponent(); } public void NameSet(string name) { label.Text = name; } } }
先ほどよりもコードがスッキリしました。動きを確認してみましょう。
いい感じです。今回行った方法の中で一番良さそうです。
4.遷移先のページのBindingContextに渡す(2019/3/19 追記)
以下のようにSecondPageのBindingContextにMainPageのentryを渡し、SecondPageのLabelにバインドする方法でもできました。
MainPage.xaml.cs
using System; using Xamarin.Forms; namespace XF_NavigationPage { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } void Handle_Clicked(object sender, EventArgs e) { Navigation.PushAsync(new SecondPage() { BindingContext = entry }); } } }
SeconaPage.xaml
<?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="XF_NavigationPage.SecondPage"> <ContentPage.Content> <StackLayout VerticalOptions="Center"> <Label Text="前のページから受け取った値" HorizontalOptions="Center"/> <Label Text="{Binding Text}" HorizontalOptions="Center"/> </StackLayout> </ContentPage.Content> </ContentPage>
動きは3と同じだったので省略します。
まとめ
今回のような簡単な場合はコードビハインドに書くだけでいいのかもしれませんが、やはりしっかりやるならMVVMを使ってやった方がいいのではないかと思いました。それについては調べてみようと思います。