概要
- 自前でアプリのメニュー+Frameを準備して、そのFrameからNavigationServiceを生成するケース
- メニュー部分とFrame部分で別々のDataContext(ViewModel)を扱う必要があるが
- FrameのDataContextがnull以外だとNavigationService側の実装が「もうViewModel注入済みやな」と判断してViewModelが生成されない
- 結論:自前FrameからNavigationServiceを生成する場合はDataContext伝播に気を付けよう
環境
Uno.Prism.Unity.Uno 7.1-pre4
(本家のPrism.Unity.Windowsと同じなはず)
問題: NavigationAsyncしても xxxPageViewModelが生成されない
Prism.Unityでは自前定義のFrameに対してNavigationServiceを都度生成することができます。アプリで複数のFrameでページ表現を別々に管理したり、あるいは複数ウィンドウで別々のFrameをもたせてそこでページを管理する場合に活躍します。(ページナビゲーションのパラメータ渡しがやりやすいだとか、ページVMの注入を自動で紐づけてくれるだとか)
そこで以下のようなNavigationServiceを作ってみると…
// PrismApplicationを継承したAppクラス内として読んでください
public static IPlatformNavigationService NavigationService { get; private set; }
public override void OnInitialized()
{
// アプリのルートUIを作成
var layout = new ApplicationCoreLayout();
NavigationService = Prism.Navigation.NavigationService.Create(layout.MyFrame, Gestures.Back, Gestures.Forward, Gestures.Refresh);
Container.GetContainer().RegisterInstance<INavigationService>(NavigationService);
Window.Current.Content = layout;
Window.Current.Activate();
}
ApplicationCoreLayoutはアプリ側で作成したNavigationView等Frame x:Name="MyFrame"を持っていて、MyFrameと紐付いたNavigationServiceを作成してDIコンテナに登録しています。
このとき、ApplicationCoreLayoutもMVVMでやりたいので、DataContextに対してApplicationCoreLayoutViewModel
を設定します。そうするとApplicationCoreLayout.DataContextがMyFrameのDataContextに伝播します。
それだけなら問題ありませんが、MyFrameで読み込まれる「××Page」にまでMyFrameのDataContextが伝播してしまうことが問題になります。
Prism.UnityのFrameFacadeによるViewModelのDIは「Page.DataContext
がnullならページナビゲーション向けのViewModelをDIするよ」と判断しているため、Page.DataContextがFrameから伝播してしまっているとViewModelがページに設定されない(ViewModelがそもそも生成されない)ことになります。
(実際の処理は Prism.Windows/Navigation/FrameFacade.cs のOrchestrateAsync
を参照のこと)
解決:Frame.DataContext = null を明示的に設定
この問題を回避するにはFrame.DataContext = nullを明示的に設定するだけで十分のようです。
<!-- Frame内のPage.DataContextにDataContextを伝播させないようnullを明示的に設定
Prism.Unityの -->
<Frame x:Name="MyFrame" DataContext="{x:Null}" />
これでOK。
以上、Frameが絡むDataContext伝播で事故った話でした。
あと Uno Platform がすごそうなんでよかったらチェックして見てね。UWPアプリをC#+Xamlで作ったらAndroidとiOSもアプリが出来る!(XamarinベースでUWPのUIを各プラットフォームでエミュレートしてるっぽい)