CocosSharp.FormsからXamarin.Formsのメソッドを実行する方法

#前フリ
[CocosSharp公式](https://developer.xamarin.com/guides/xamarin-forms/advanced/cocossharp/)やCocosSharp第一人者@hiro128_777さんの[この記事](http://hiro128.hatenablog.jp/entry/2016/12/14/000147)の様に、Xamarin.Forms側からCocosSharpのコンテンツ（例ではCCDrawNode/CCSprite）を操作することは例示されています。

#この記事趣旨
今回はその逆、CocosSharp.Forms側からXamarin.Forms側のメソッドを呼び出す方法をサンプルコードとともに紹介したいと思います。

#環境等
- Xamarin.Forms 2.3.3.175
- Prism.Forms 6.2
- CocosSharp 1.7.1
- CocosSharp.Forms 1.7.1

#ユースケース
Prismを導入したXamarin.Forms画面があり、各種コンテンツがContentPageごとに用意されているアプリを作ったとします。
ゲーム自体はとあるContentPageに最大画面で表示されており、ゲームの終了時にXamarin.Forms側に用意した画面遷移用のメソッド呼び出してアプリのホーム画面を表示したい要件だとします。

#サンプルコード

まず、Xamarinの標準的な方法でContentPageを構成します。
このページに全画面表示したCocosSharpViewを配置し、後述するViewModelに用意して公開したICommandメソッドをCocosSharp側に渡してやり、そっちからキックすることでXamarin.Forms側のメソッドを起動する形になります。

```csharp:GamePage.xaml.cs
public partial class GamePage : ContentPage
{
    public GamePage()
    {
        InitializeComponent();

        //対応するViewModelを割り出し、プロパティ公開しているICommandを取り出す
        var viewModel = this.BindingContext as GamePageViewModel;
        ICommand cmd = null;
        if (viewModel != null)
        {
            cmd = viewModel.GameFinishCommand;
        }

        var gameView = new CocosSharpView()
        {
            HorizontalOptions = LayoutOptions.FillAndExpand,
            VerticalOptions = LayoutOptions.FillAndExpand,
            ViewCreated = (object sender, EventArgs e) =>
            {
                var gv = sender as CCGameView;
                gv.DesignResolution = new CCSizeI(Helpers.Settings.AppWidth, Helpers.Settings.AppHeight);
                gv.ResolutionPolicy = CCViewResolutionPolicy.ShowAll;
                //CocosSharp側の基底LayerにStatic公開しているICommandプロパティに渡してやる
                BaseLayer.GameEndCommand = cmd;
                gv.RunWithScene(GameStartLayer.GetScene(gv));
            }
        };

        this.Content = gameView;
    }
}
```

```csharp:GamePageViewModel.cs
public class GamePageViewModel : PrismBaseViewModel
{
    public GamePageViewModel(INavigationService navigationService)
        : base(navigationService)
    {
        this.SetCommand();
    }

    public ICommand GameFinishCommand { get; protected set; }

    private void SetCommand()
    {
        //プロパティ公開しているコマンドでしかるべき処理（今回はPrism画面遷移）
        this.GameFinishCommand = new DelegateCommand(async () =>
        {
            if (this.IsBusy) return;
            this.IsBusy = true;
            await this.NavigationService.NavigateAsync(Consts.NavigationUrl.HOME_PAGE);
            this.IsBusy = false;
        }, () => !this.IsBusy);
    }
}
```

```csharp:BaseLayer.cs
public abstract class BaseLayer : CCLayerColor
{
    public void GameEnd()
    {
        //NOTE:リソースの解放やらなにやら

        //終了処理として受け渡されているコマンドを実行
        //中身はViewModelで定義の通りゲームページからホームページへの遷移
        //UIスレッドで動かす必要があるためDevice.BeginInvokeOnMainThreadをかませる
        Device.BeginInvokeOnMainThread(() =>
        {
            GameEndCommand.Execute(null);
        });
    }

    public static ICommand GameEndCommand { get; set; }
}
```

#最後に
紹介した方法でCocosSharp側から任意のXamarin.Forms側メソッドを実行できると思います。
Xamarin/Prismに詳しいわけではないのでコレがベストプラクティスではないかも知れません。。
　※その場合はコメントでアドバイスいただけるとうれしいです。

それでは楽しいプログラミングライフを！