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

.Net系プログラムで勉強したこととか嵌ったことについて書いたりします。

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も気になってるんですよね

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

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