はまったりひらめいたり…とか…

Angularや.NETやAzureやその他色々。

Xamarin.Formsのサンプルで遊んでみたよ!

Evoleve2016始まりましたね!

どんな発表があるかドキドキですね!

サンプルで遊ぶ

Hello, iOSですとかHello Androidもいいですけど

実際にゴリゴリ動いているのを見るとソースをいじるのが楽しくなりますよね。

今回、Xamarin.FormsのGitHubで提供されている、2つのSampleを組み合わせて遊んでみました。


github.com


今回組み合わせたサンプル2つ
xamarin-forms-samples/Navigation/LoginFlow/

xamarin-forms-samples/Navigation/MasterDetailPage/

使用しているサンプル名称を見ていただければわかる通りですが

ログイン画面でログイン→MasterDetailページに遷移

といった単純な構成です。とっかりりとしてはこれぐらいがちょうどいいですね。

※MasterDetailPageの構成なんかは、上記のGitHub内にScreenShotがありますのでご覧くださいませ。

まずはサンプルソースをざっと眺めてみる

LoginFlow

開いて早速エラーが出まくったり、MVVMチックな構成ではなかったりと

気になるところは多々ありますが、サンプルを下敷きに新しく作り直せば問題ありません。

LoginPageCS.cs
LoginPage.xaml
まず上の2つのファイルがその名の通りLoginPageのView部分ですね

C#のコードのみでも構成できますし、XAMLを使用することも可能です。

WPF使いの方ならXAML安定ですね。


Sampleを組み合わせるうえでLogInPage側の肝のLogicは下記部分ですね。
(実際には色々基本的な部分で重要な部分はいっぱいありますよ!)

LoginPage.xaml,cs

async void OnLoginButtonClicked (object sender, EventArgs e)
{
	var user = new User {
		Username = usernameEntry.Text,
		Password = passwordEntry.Text
	};

	var isValid = AreCredentialsCorrect (user);
	if (isValid) {
		App.IsUserLoggedIn = true;
		Navigation.InsertPageBefore (new MainPage (), this);
		await Navigation.PopAsync ();
	} else {
		messageLabel.Text = "Login failed";
		passwordEntry.Text = string.Empty;
	}
}

入力されたユーザー名称とパスワードが一致しますかー?というものを確認。

Navigation.InsertPageBeforeで遷移先のページを生成し、Navigation.PopAsyncでページ遷移を行っています。

今回やりたいのは、このMainPageをMasterPageDetailのSampleで使用されているMain画面にするだけです。

MasterDetailPage

こちらはLogic部分で変更する箇所はありません。

ただ、押さえておきたいのは、下記の内容です。

MainPage.xaml

<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" 
				  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
				  xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
				  x:Class="MasterDetailPageNavigation.MainPage">
  <MasterDetailPage.Master>
  	<local:MasterPage x:Name="masterPage" />
  </MasterDetailPage.Master>
	<MasterDetailPage.Detail>
		<NavigationPage>
			<x:Arguments>
				<local:ContactsPage />
			</x:Arguments>
		</NavigationPage>
	</MasterDetailPage.Detail>
</MasterDetailPage>

CSのコードハイライトはちと役不足感があるけどまぁいいか

MainPage.xaml.cs

public MainPage ()
{
	InitializeComponent ();

	masterPage.ListView.ItemSelected += OnItemSelected;

	if (Device.OS == TargetPlatform.Windows) {
		Master.Icon = "swap.png";
	}
}

void OnItemSelected (object sender, SelectedItemChangedEventArgs e)
{
	var item = e.SelectedItem as MasterPageItem;
	if (item != null) {
		Detail = new NavigationPage ((Page)Activator.CreateInstance (item.TargetType));
		masterPage.ListView.SelectedItem = null;
		IsPresented = false;
	}
}

MainPageがMasterとDetailに分かれており、それぞれページが指定されています。

Maseterがわが「MasterPage」Detail側が「ContactsPage」です。

リストアイテムの選択処理はMasterPage(子)のCSではなく、MainPage(親)で行われています。

XAML側7行目で配置された、MasterPageに配置されたListViewのEventをキャッチし、選択処理が行われています。

NavigationPageでページ遷移を行っています。

item.TargetTypeはMainPageやContentPage等のXAMLで作成したページ名称ですね。

では組み合わせてみよう

前述の通り、Sampleをそのままですとエラーが多すぎるため

新しいソリューションを立ち上げて、ソースを組み合わせていきます。

途中過程はすっとばしまして、ソリューションの構成は下記の通りです。
f:id:TakasDev:20160424235640p:plain

MVVMっぽい構成になりました。

Mock内にはSampleUserをつっこんでます。

ViewModel内には、UserViewModelとMenuのViewModelですね。

Xamarin.Droid,/iOsにはResourceとして、アイコン情報を登録しただけです。

Droidは \Resources\drawableに

iOSは \Resourcesに格納しました。

デバイス側にはコードを1行も記述していないです。スバラシイ

実行

f:id:TakasDev:20160425000959p:plain

ログインページでた!

が、ログイン処理時にエラー!!
f:id:TakasDev:20160425001100p:plain

やはりすんなりはいかないか…

エラーの内容を確認すると

「Navigationページは1ページ1個しか認めませんよ!」という内容のようです。

そりゃそうだ。

では、ここでXAMLを見ていきます。

たしかに、MasterDetailを使用しているMainPage.xamlタグを使用しています(上述参照)。

しかし、LoginPageにはタグは存在しません。

では、どこにあるのでしょうか。

App.cs

public App()
{
    if (!IsUserLoggedIn)
    {
        MainPage = new NavigationPage(new LoginPage());
    }
    else
    {
        MainPage = new NavigationPage(new MainPage()); ;
    }
}

App.csでアプリケーション立ち上げ時のページを指定していますが

ここの部分で、LoginPageがNavigationPageとしてNewされています。

だから、ログインアクション時の、「Navigation.InsertPageBefore (new MainPage (), this)」が使用できるわけですね。

対処療法的に対処してみる

変更後のMainPage.xaml

<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
				  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
				  xmlns:local="clr-namespace:XamarinSample.Views;assembly=XamarinSample"
				  x:Class="XamarinSample.Views.MainPage">
  <MasterDetailPage.Master>
    <local:MasterPage x:Name="MasterPage" />
  </MasterDetailPage.Master>
  <MasterDetailPage.Detail>
    <!--<NavigationPage>-->
    <!--<x:Arguments>-->
    <local:ContactsPage />
    <!--</x:Arguments>-->
    <!--</NavigationPage>-->
  </MasterDetailPage.Detail>
</MasterDetailPage>

完全に対処療法ですが

すでにLoginPageからNavigationを使用したページ遷移が行われているわけですし

改めてNavigationPageタグの宣言する必要ないよね?ってことでNavigationタグを消してみました。

ログイン通った!

f:id:TakasDev:20160425002645p:plain

MasterDetail側のページ遷移もうまく動作しているようです。

f:id:TakasDev:20160425002755p:plain


いや、でも対処療法だし、もうちょっとちゃんと眺めようとは思います。

まとめ

  • Sampleソースは見るのもいじるのも勉強になります。
  • いきなり作りたいものを作るより、Sampleを組み合わせるほうがイメージしやすいかも?

EmployeeDirectoryのSampleを流用して、ユーザー管理画面を作ってみようかなと考えています。

あぁ、でもBotFrameworkも気になってるんですよね

まぁ、明日から月曜なんで、遊ぶのはしばらくお預けです…。

ものすごい長くなったんで次回は抑えれるよう頑張ります。