Prism for Xamarin.Forms を使ってみた！

本エントリーは [Xamarin Advent Calendar 2016 (その１) 22日目](http://qiita.com/advent-calendar/2016/xamarin)のエントリーです。

Xamarin のイベントに参加するようになり、Prism for Xamarin.Forms のことを知りずっと気になっていました。まだ、一度も触ったことがなかったので、今回の機会が良いと思いこのテーマにしてみました。

ただ、Prism for Xamarin.Forms だけを使ってみるのもつまらないと思い、位置情報系のエンジニアでもあるので地図のテーマと絡めて利用してみました。

個人的には普段、Rails などの MVC モデルの開発に慣れているぶん、MVVM モデルとの区別がまだ分からないところもありましたが、Prism を利用することで、MVVMアーキテクチャを実現するパターンの理解にもつながり、それが簡単にできることに驚きつつ、感動しました。でも、まだ自分の言葉では説明できないのでもっと勉強して理解する必要があると感じています。

## Prism for Xamarin.Forms について
Prism for Xamarin.Forms をはじめるにあたり、Xamarin のイベントなども良く発表されている @Nuits さんの記事 [Prism for Xamarin.Forms入門](http://www.nuits.jp/entry/2016/08/22/173858) が非常に分かりやすく今回はこちらを参考にして実装しました。Prism for Xamarin.Forms についてもかなり詳しく載っています。

## Prism for Xamarin.Forms のアドイン追加とプロジェクトの作成
今回は Mac OS で Xamarin Studio を利用して開発しました。メニューの [Xamarin Studio Commiunity] → [アドイン] でアドイン マネージャーが表示されますので、Prism Template Pack をインストールします。インストールすることで、新しいプロジェクトを作成するときに Prism Unity App が選択できるようになります。　  

####1. Prism Template Pack のインストール
![2016-12-22_1635.png](https://qiita-image-store.s3.amazonaws.com/0/102251/329833f3-b5ae-8993-a283-46f9d665f6f3.png)

####2. プロジェクトの作成
![2016-12-22_1636.png](https://qiita-image-store.s3.amazonaws.com/0/102251/c666da6e-e1f7-aff7-5d89-e689cbf9dfec.png)

![2016-12-22_1637.png](https://qiita-image-store.s3.amazonaws.com/0/102251/79c88b3d-ed4e-22cd-fb42-237e5d147ba3.png)

####3. ビルドエラー
なぜかここでビルドエラーになってしまいます。
![2016-12-22_1650.png](https://qiita-image-store.s3.amazonaws.com/0/102251/d9657d90-ef8e-5bc6-a90d-c21a83c792cd.png)

**AppDelegate.cs** で以下を追加することで回避できました。

```C#:AppDelegate.cs
using Microsoft.Practices.Unity;
using Prism.Unity;
```
無事にエラーも解消できて初期画面を起動することができました。
![2016-12-22_1656.png](https://qiita-image-store.s3.amazonaws.com/0/102251/d8e371aa-b049-eb1c-b7c4-5a260218b687.png)

## Prism for Xamarin.Forms を利用した地図開発
今回地図を活用してみたいと思い、先日 [Esri](http://www.esri.com/) からリリースされた [ArcGIS Runtime SDK for .NET](https://developers.arcgis.com/net/latest/) の Esri.ArcGISRuntime.Xamarin.Forms を利用しました。10月の [Xamarin 入門者の集い](https://jxug.connpass.com/event/39086/) で [LT] (http://www.slideshare.net/TakahiroKamiya3/xamarin-20161026) でも発表しましたが、ようやく11月に正式リリースされました。

パッケージを追加します。
![2016-12-22_1645.png](https://qiita-image-store.s3.amazonaws.com/0/102251/85b57a36-2459-0f0f-4066-e68f073e4448.png)

今回は、Prism for Xamarin.Forms でメインページから遷移先のページとして、3ページ用意して、各3ページに対して実装していきました。各ページの追加やページからメインページに戻る方法などは、すべて [Prism for Xamarin.Forms入門](http://www.nuits.jp/entry/2016/08/22/173858) を参考にすることで、簡単に実現できました。あとは、各ページで自分が実現したいこと（今回は地図表示など）に集中して開発することができました。

![2016-12-22_1701.png](https://qiita-image-store.s3.amazonaws.com/0/102251/4b194c06-b3e7-5696-8f34-7a3f55494010.png)

こちらが、メインページで、今回は独断と偏見で
**1. ３D地図**
**2. 背景地図の切り替え**
**3. 地図のスクリーンショット**
を各ページで実装してみました。これ以外にも色々なことができるんですが、今後他の機能についてはブログなどでも紹介していければとも思っています。

![2016-12-22_2118.png](https://qiita-image-store.s3.amazonaws.com/0/102251/afd3f743-5277-1148-fc89-eb637a9aa0b5.png)

####1. ３D地図
![2016-12-22_2119.png](https://qiita-image-store.s3.amazonaws.com/0/102251/501e9151-e72b-b78f-0e07-ecbf891b165e.png)

Esri.ArcGISRuntime.Xamarin.Forms では、２Dと３Dの地図表現が可能で、３Dには、Scene サービスを利用します。

Scene クラスで表示したい背景地図を作成し、Scene クラスで作成した背景地図を表示するには、[SceneView](https://developers.arcgis.com/net/latest/uwp/api-reference//html/T_Esri_ArcGISRuntime_UI_Controls_SceneView.htm) に Scene を割り当てることで 3D の地図を簡単に表現することができます。
以下のソースを見ていただければ分かるかと思いますが、XAML で SceneView を定義して、Next1Page.xaml.cs 側で Scene クラスを利用して背景地図を作成しています。作成した Scene を SceneView に割り当てます。ですので、たとえば、背景地図の上に別の地図などを表示したい場合は、Scene クラス に表示したい別の地図レイヤを追加していくことで、背景地図上に色々な地図レイヤを表現することが可能です。

```C#:Next1Page.xaml.cs
// create a new scene with a topographic basemap
var myScene = new Scene(Basemap.CreateTopographic());


// add the new scene to the scene view
MySceneView.Scene = myScene;
```
```xml:XAML
<esriUI:SceneView x:Name="MySceneView" />
```

3D の地図表現については、英語ですがこちらにもさらに詳しくありますので、ご興味のある方はぜひ覗いてみてください！
[3D の地図表現について（Display a scene）](https://developers.arcgis.com/net/latest/forms/guide/display-a-scene.htm)

####2. 背景地図の切り替え

![2016-12-23_0036.png](https://qiita-image-store.s3.amazonaws.com/0/102251/04e900dd-a225-9f9f-a2ff-9b8ed6d7b621.png)

背景地図は、XAML に背景地図を選択できるボタンを設置しています。そのボタンがクリックされると、背景地図一覧が表示されます。一覧から選択された背景地図に対して、MyMapView.Map.Basemap に Basemap クラスで作成した背景地図を設定してあげます。ちなみに、Basemap クラスでは、他にも多くの[背景地図](https://developers.arcgis.com/net/latest/uwp/api-reference//html/T_Esri_ArcGISRuntime_Mapping_BasemapType.htm)を扱うことができます。

```C#:Next2Page.xaml.cs
private async void OnChangeBasemapButtonClicked(object sender, EventArgs e)
{
	// Show sheet and get title from the selection
	var selectedBasemap =
		await DisplayActionSheet("Select basemap", "Cancel", null, titles);

	// If selected cancel do nothing
	if (selectedBasemap == "Cancel") return;

	switch (selectedBasemap)
	{
		case "Topo":

			// Set the basemap to Topographic
			MyMapView.Map.Basemap = Basemap.CreateTopographic();
			break;

		case "Streets":

			// Set the basemap to Streets
			MyMapView.Map.Basemap = Basemap.CreateStreets();
			break;

		case "Imagery":

			// Set the basemap to Imagery
			MyMapView.Map.Basemap = Basemap.CreateImagery();
			break;

		case "Ocean":

			// Set the basemap to Imagery
			MyMapView.Map.Basemap = Basemap.CreateOceans();
			break;

		default:
			break;
	}
}

private void initBasemap()
{
    // Create new Map with basemap
    Map myMap = new Map(Basemap.CreateTopographic());

	// Assign the map to the MapView
	MyMapView.Map = myMap;
}
```
```xml:XAML
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="auto" />
    </Grid.RowDefinitions>
    <esriUI:MapView x:Name="MyMapView" />
    <Button x:Name="changeBasemapButton" Text="背景地図の変更" Clicked="OnChangeBasemapButtonClicked" Grid.Row="1"/>
  </Grid>
```

![2016-12-22_2120.png](https://qiita-image-store.s3.amazonaws.com/0/102251/fb9585b0-b45d-6ed4-881b-fc9e05951584.png)

![2016-12-22_2121.png](https://qiita-image-store.s3.amazonaws.com/0/102251/6faec2cb-3151-0bed-bdff-26ac208bed9b.png)

![2016-12-22_2122.png](https://qiita-image-store.s3.amazonaws.com/0/102251/85fa8611-4739-1a42-4414-9fd59bcbae38.png)

####3. スクリーンショット
最後はスクリーンショットです。この機能はベータ版ではなかったので自分でもこんな機能があるのかとも思ってしまいました。まあ、何に利用できるかは置いておき単純に試してみました。

どうやら、GeoView の [ExportImageAsync メソッド](https://developers.arcgis.com/net/latest/uwp/api-reference//html/M_Esri_ArcGISRuntime_Xamarin_Forms_GeoView_ExportImageAsync.htm)を使用しているようです。試したところ、表示している範囲をちゃんとスクリーンショットしてくれます。詳細は....

```C#:Next3Page.xaml.cs
private async void OnTakeScreenshotClicked(object sender, EventArgs e)
{
	// Export the image from mapview and assign it to the imageview
	var exportedImage = await MyMapView.ExportImageAsync();

	// Create layout for sublayers page
	// Create root layout
	var layout = new StackLayout();

	var closeButton = new Button
	{
		Text = "Close"
	};
	closeButton.Clicked += CloseButton_Clicked;

	// Create image bitmap by getting stream from the exported image
	var buffer = await exportedImage.GetEncodedBufferAsync();
	byte[] data = new byte[buffer.Length];
	buffer.Read(data, 0, data.Length);
	var bitmap = ImageSource.FromStream(() => new System.IO.MemoryStream(data));
	var image = new Image()
	{
		Source = bitmap,
		Margin = new Thickness(10)
	};

	// Add elements into the layout
	layout.Children.Add(closeButton);
	layout.Children.Add(image);

	// Create internal page for the navigation page
	var screenshotPage = new ContentPage()
	{
		Content = layout,
		Title = "Screenshot"
	};

	// Navigate to the sublayers page
	await Navigation.PushAsync(screenshotPage);
}
```

![2016-12-22_2123.png](https://qiita-image-store.s3.amazonaws.com/0/102251/e3be5db1-f764-1fb6-e59e-7cb9620da104.png)

![2016-12-22_2124.png](https://qiita-image-store.s3.amazonaws.com/0/102251/b811e086-090c-f4f6-a183-753351bf3910.png)

## まとめ
今回、Prism for Xamarin.Forms を利用して、簡単にページ含めて、画面遷移が実装できたのは感動しました。ほんとに簡単で時間もまったくかかっていません。実際にページ遷移にパラメータの引き渡しなどが入ってくると少し難しくなるのでしょうか。Prism for Xamarin.Forms についてもっと理解したいと思いますので、[Prism for Xamarin.Formsの画面遷移 10のベストプラクティス](http://www.nuits.jp/entry/best-practice-of-prism-for-xamarin-forms)についても勉強していきたいと思います。

今回作成した各サンプルは、こちらの [Github](https://github.com/ValueCreation/ArcGISRuntimeSamplesXamarin/tree/master/ArcGISRuntimeSamples02/PrismForms) にも公開していますので、よろしくお願いします！

２３日になってしまいましたが、なんとか書き終えることができました！

####Xamarin はいいぞ！