Xamarin.Forms
Xamarin.Mac

Xamarin.Forms for MacがStoryboardと仲良くする方法

この記事は [初心者さん・学生さん大歓迎!] Xamarin その1 Advent Calendar 2017 の16日目の記事です。

題について

勢いでサクッとつけてしまった題ですが、思ってたのとちょっと違うところです。
実際には、「 他プラットフォームとの互換性を最大限に維持しつつ Xamarin.Forms for MacがStoryboardと仲良くする方法」ですね。

もっと標準コンロールで

Storyboardでは

101.png

こういうコントロールを出すのは楽なのに。
(もちろん、こいつだとsegue一発なんでXamarin.Formsでもコード書きゃ終いですが)
でもDataBindingやら他機種へのポーティングを考えるとXamarin.Formsのコード使えたら楽なのに。

というわけで、いいとこ取りする簡単な方法です。

実現方法

理屈:Xamarin.Forms

Xamarin.Forms for Macの動きとして。

  • Forms.Init()は適当な時に呼び出しても良い
  • Forms.Init()はFormsApplicationDelegate.LoadApplicationの前に呼びださなければいけない
  • ApplicationのMainPageは設定されていなくても良い
  • ApplicationのMainPageが設定されていなければ、FormsApplicationDelegate.Windowは設定されていなくても良い
  • FormsApplicationDelegate.LoadApplicationは最初のPage操作の前に呼び出されていなければいけない
  • Xamarin.FormsのPageからNSViewControllerを作れる

理屈:Storyboard

また、Storyboard起動からの呼び出し順は、

  1. FormsApplicationDelegate.<<constructor>>
  2. NSViewController.ViewDidLoad
  3. FormsApplicationDelegate.DidFinishLaunching

です。

理屈:統合

なので、本来ならFormsApplicationDelegate.DidFinishLaunchingでXamarin.Formsの処理を行いますが、その流れを変えて。

  1. アプリ起動、UI始動までStoryboardで行う
  2. Forms.Init()とLoadApplicationはFormsApplicationDelegate.<<constructor>>で行う
  3. Application.MainPageを設定しない
  4. FormsApplicationDelegate.Windowも設定しない
  5. 表示関連はPageで用意しておき、ViewControllerにくっつける
  6. くっつけるのはNSViewController.ViewDidLoadで行う
  7. データの保持、更新処理はXamarinのBindingObjectに納める
  8. BindingObjectからのデータ更新はPage側で受け、表示する

という処理にします。

作ってみた

Githubに作ったものを置いてみました1

AppDelegate : Storyboard

何もしないXamarin.Forms.Applicationのサブクラス(App)を作り、それをLoadApplicationで設定しています。
これで、StoryboardのDelegateとして読み込まれ、Xamarin.Forms的には初期化を行い、WindowはStoryboardのものを使うように設定しています。

他プラットフォームでは、LoadApplicationで設定しているのはHelloWorldAppです。

MainData : Xamarin.Forms

埋め込みリソースとして登録してあるJSONを読み込み、本棚データとして保持します2

TitlesViewController : Storyboard

StoryboardでメインウインドウのViewControllerとして設定されます。
ViewDidLoadでTitleListPageを子ViewControllerとして設定しています。

TitleListPage : Xamarin.Forms

MainDataをBindingContextとしてわりつけ、表示している本棚の中の本の一覧を表示します。
他プラットフォームだと、MasterDetailPageのDetailにわりつけてメインのページになっています。

BookshelvesViewController : Storyboard

ウインドウにわりつけられたToolBarのボタンからPopupする本棚の一覧を表示するViewControllerです。
ボタン押下でPopupまではStoryboardで設定されています。
ViewDidLoadでBookshelfListPageを子ViewControllerとして設定しています。

BookshelfListPage : Xamarin.Forms

MainDataをBindingContextとしてわりつけ、本棚一覧を表示します。
ポップアップの中身です。
他プラットフォームだと、MasterDetailPageのMasterにわりつけてます。

結論

意外に簡単にStoryboardと統合できました。
このやり方は、 Page.CreateViewController におんぶにだっこしてもらって実現できています3
MVVMで分けるのは微妙ではありますが、入力する量も少なくていいところではないかと思います。


  1. アイコンはICOOON MONOさんのものを使用しています。 

  2. 作った後に気づきましたが、コンストラクタはprivateの方が良いですねぃ。 

  3. iOSでの同じやり方は意外に難しそうです。ListViewェ…。