Xamarin.FormsのPrismソリューションにUWPプロジェクトを追加する

Xamarin.FormsでPrismを使ってAndroid限定のアプリを作っていたのですが、手持ちのWindows10Mobile端末でも使えるようにしたいと思い、UWPプロジェクトを追加することにしました。

参考にしたのはstackoverflowの[こちらのスレッド](https://stackoverflow.com/questions/41192203/how-can-i-add-a-uwp-target-to-an-existing-xamarin-forms-project)です。
Prismではない通常のXamarin.FormsソリューションにおけるUWPプロジェクトの追加方法ですが、MainPage.xaml.csの変更内容に少し違いがあるだけでほぼ同じです。
Prismを使わない場合はstackoverflowの手順に従えばOKです。

ちなみにUWPプロジェクトを追加するアプリケーションのメインページはこんな感じです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/78da3b90-0159-38dd-691a-28a4e4e8203b.png" title="" alt="Screenshot_20190124-110026.png" width="60%" height="" >

#前提
Visual Studioで「ユニバーサルWindowsプラットフォーム開発」のワークロードをインストールしておいてください。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/d908101a-16be-51dc-6f11-b7d286b82efe.png" title="" alt="image.png" width="60%" height="" >

#追加前のソリューションの構成
ご覧のとおり、Androidプロジェクトしかありません。
<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/020036c3-3860-6718-d7dd-8c9e0b84b6e5.png" title="" alt="image.png" width="60%" height="" >

#UWPプロジェクトを追加
ソリューションエクスプローラーで、ソリューション名で右クリックして`追加`→`新しいプロジェクト`を選択します。
<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/498a7028-28a8-07a0-f9b3-138801176215.png" title="" alt="image.png" width="60%" height="" >


追加するプロジェクトは`空白のアプリ　（ユニバーサル　Windows）`です。
プロジェクトの名前と追加する場所を入力しますが、ここで注意が必要です。

- 名前は他のプロジェクトと命名規則を揃える
- 場所は他のプロジェクトとフォルダ階層が同じになるようにする

UWPプロジェクトの名前は`ソリューション名.UWP`とする必要があり、今回の例では`TakeMeThereXamarinForms.UWP`となります。

Xamarin.Formsのフォルダ構成では、ソリューションフォルダの下にもう一つ同名のフォルダがあり、その中に各プロジェクトのフォルダが入っているので、今回の例ではプロジェクトを追加する場所として`C:\temp\TakeMeThereXamarinForms\TakeMeThereXamarinForms`を指定します。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/af2662c8-4fc9-d13f-4af8-36ae4cb13f0f.png" title="" alt="image.png" width="60%" height="" >

OKボタンを押すと、次にUWPプロジェクトのターゲットバージョンの指定を求められます。
2019年1月23日時点で、Xamarin.Formsは`.Net Standard 2.0`のライブラリを使うようになっていて、そのため、プラットフォームの最小バージョンとして`Windows 10 Fall Creators Update(10.0;ビルド 16299)`以上を選択する必要があります。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/eb89b884-9719-41ff-bae9-60f27e3f1e71.png" title="" alt="image.png" width="60%" height="" >

ソリューションエクスプローラーにUWPプロジェクトが追加されました。
<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/3c20d2e5-ed4f-e47e-e8d0-465452a9566a.png" title="" alt="image.png" width="60%" height="" >

アプリのソリューションのフォルダを見てみると、以下のようにAndroidプロジェクトと同じ階層にUWPプロジェクトができています。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/2eca8430-425c-77c3-293c-4bdb949fe266.png" title="" alt="image.png" width="60%" height="" >


#Xamarin.Formsパッケージのインストール
UWPプロジェクトにXamarin.Formsパッケージをインストールします。
UWPプロジェクト名の上で右クリックして`NuGetパッケージの管理`を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/245438/ccdd2cac-e0ef-7062-100a-2f218130cb83.png)

`参照タブ`で「xamarin.forms」を検索してインストールします。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/ffeeceba-b6ae-90a7-e675-92b00ac07c02.png" title="" alt="image.png" width="60%" height="" >

このとき、インストールする`Xamarin.Forms`のバージョンは他のプラットフォームのプロジェクトにインストールされているバージョンと同じバージョンを選択してください。
すべてのプラットフォームのプロジェクトで同じバージョンの`Xamarin.Forms`を使用することが重要です。

#App.xaml.csの変更
UWPプロジェクトのApp.xaml.csに以下の変更を加えます。
`rootFrame.NavigationFailed += OnNavigationFailed;` の下に`Xamarin.Forms.Forms.Init(e);`を追加します。

```csharp
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // ウィンドウに既にコンテンツが表示されている場合は、アプリケーションの初期化を繰り返さずに、
            // ウィンドウがアクティブであることだけを確認してください
            if (rootFrame == null)
            {
                // ナビゲーション コンテキストとして動作するフレームを作成し、最初のページに移動します
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                //これを追加
                Xamarin.Forms.Forms.Init(e);
```

#MainPage.xamlの変更
次にUWPプロジェクトのMainPage.xamlに変更を加えます。
`xmlns:forms="using:Xamarin.Forms.Platform.UWP"`を追加し、`Page`タグを`forms:WindowsPage`とします。

変更後は以下のとおりです。

```xml
<forms:WindowsPage
    x:Class="TakeMeThereXamarinForms.UWP.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TakeMeThereXamarinForms.UWP"
    xmlns:forms="using:Xamarin.Forms.Platform.UWP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>

    </Grid>
</forms:WindowsPage>
```

#MainPage.xaml.csの変更
UWPプロジェクトのMainPage.xaml.csに以下の変更を加えます。
まず、`MainPage`クラスが`Page`クラスを継承していますが、その継承を削除します。

```csharp:変更前
public sealed partial class MainPage : Page
```

```csharp:変更後
public sealed partial class MainPage
```

次に`MainPage`メソッドに`LoadApplication(new TakeMeThereXamarinForms.App(new UwpInitializer()));`を追加します。

```csharp
    public sealed partial class MainPage 
    {
        public MainPage()
        {
            this.InitializeComponent();

            //追加
            LoadApplication(new TakeMeThereXamarinForms.App(new UwpInitializer()));
        }
    }
```

そして`UwpInitializer`クラスを追加します。

```csharp
    public class UwpInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            // Register any platform specific implementations
        }
    }
```

最後に、`IPlatformInitializer`と`IContainerRegistry`のために以下の2つを`using`で追加します。

最終的に`MainPage.xaml.cs`は以下のようになります。

```csharp
using Prism;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// 空白ページの項目テンプレートについては、https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x411 を参照してください

namespace TakeMeThereXamarinForms.UWP
{
    /// <summary>
    /// それ自体で使用できる空白ページまたはフレーム内に移動できる空白ページ。
    /// </summary>
    public sealed partial class MainPage 
    {
        public MainPage()
        {
            this.InitializeComponent();

            LoadApplication(new TakeMeThereXamarinForms.App(new UwpInitializer()));
        }
    }

    public class UwpInitializer : IPlatformInitializer
    {
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            // Register any platform specific implementations
        }
    }
}
```

#動かしてみる
UWPプロジェクトをローカルコンピュータで実行すると、以下のように表示されました。
ターゲットプラットフォームとしてUWPを追加することができました。

<img src="https://qiita-image-store.s3.amazonaws.com/0/245438/f7d89219-7a3e-ea6b-75cb-3a91df17d11c.png" title="" alt="image.png" width="60%" height="" >