すごく久々の、UWPネタです。*1
2017年7月当初と、少し前のニュースになりますが、
こんなのがありました。*2
MS公式のGitHubはこちら。
これを見て、使ってみよう!というのが、今回の記事です。
- 紹介記事
最新のアプリ - UWP Community Toolkit の調査
HamburgerMenuとは
UWPアプリで見かける、「三」みたいなボタンで開閉する左のメニューです。
このToolkitが出るまでは、SplitView
等を使って自作する必要がありましたが、ライブラリに含まれています。
これとPrism
を組み合わせて、ナビゲーションしてみよう!という目的です。
できていないので注意!
HamburgerMenuでのページ遷移
HamburgerMenuの中には、Page
を表示できます。
上の画像で表示している、簡素な画面も、別のPage
として作成しています。
Page
表示を実現するには、こんな風に
<controls:HamburgerMenu x:Name="hamburgerMenuControl" ItemsSource="{x:Bind ViewModel.Menus}" PaneBackground="Black" Foreground="White" ItemTemplate="{StaticResource DefaultTemplate}" ItemClick="{x:Bind ViewModel.OnMenuItemClick}" OptionsItemTemplate="{StaticResource DefaultTemplate}" OptionsItemClick="{x:Bind ViewModel.OnMenuItemClick}"> <Frame x:Name="contentFrame" Foreground="Black" Loaded="contentFrame_Loaded"/> </controls:HamburgerMenu>
内部にFrame
を置き、このフレームに対し、ナビゲーションを呼び出せばよいようです。
メニューをクリックしたら画面遷移
上で、
ItemClick="{x:Bind ViewModel.OnMenuItemClick}"
と、やっていますが、これがメニュークリック時のイベントです。
x:Bind
の機能を使って、イベントを直接ViewModelとバインドして呼び出しています。
ViewModelでのイベントはこんな感じです。
private INavigationService _navigation; private INavigationService _menuNavi public void OnMenuItemClick(object sender, ItemClickEventArgs e) { var menuItem = e.ClickedItem as MenuItem; _menuNavi.Navigate(menuItem.PageName, null); }
メニューの情報はViewModelで保持しており、遷移先(menuItem.PageName
)も、そこで管理しています。
_menuNavi
は、HamburgerMenu内のナビゲーションです。
Prismのナビゲーションの仕組み
いきなり話は変わりますが…
Prismでは、標準でナビゲーション用のインターフェイスがあり、標準実装は用意されています。*3
これを、DIコンテナを通して、各ViewModelで利用できます。
この機能、大変便利なのですが、標準だと「画面全体を遷移」させます。つまり、「遷移先として指定したページを、ウィンドウ全体に表示」します。
標準のナビゲーションでHamburgerMenuを使うと、上で書いた
内部に
Frame
を置き、このフレームに対し、ナビゲーションを呼び出せばよい
という部分が実現できません。
HamburgerMenuのページ独自の遷移
既に解決されている方がいらっしゃいました。
…どうやっても埋め込みがうまくいかないので、Markdown構文で埋め込みました。
ただ、DataContextChanged
のタイミングだと、Prismではうまくいかないので、Frame.Loaded
のタイミングで行っています。*4
*Viewソース
private void contentFrame_Loaded(object sender, RoutedEventArgs e) { var vm = ViewModel; if (vm != null) { Func<string, Type> typefunc = s => Type.GetType(this.GetType().Namespace + $".{s}Page"); var frame = new FrameFacadeAdapter(contentFrame); var navi = new FrameNavigationService( frame, typefunc, new SessionStateService()); vm.ReceiveMenuNavigation(navi); } }
ViewModelには、独自のINavigationService
を受け取る入口を作っています。(受け取ったものが、_menuNavi
にセットされる)
Frame
への参照が無いと、INavigationService
は生成できないため、DIコンテナ利用は諦めています。
こうすると、Prismの邪魔をせず、HamburgerMenuのクリックで、画面遷移ができます!
…が。
戻るボタンをどうするか
画面左上に表示される「←」ボタンですが、これはあくまでPrism標準のナビゲーションのみ解決します。
そのため、上のようにオレオレナビゲーションを行うと、HamburgerMenu内では戻る機能が使えません。*5
ここが、できていない部分です。
正直、複数ナビゲーション(複数Frame)を使った場合のナビゲーションをどう作るのが良いのか、分かっていません。
複数のナビゲーションを繋ぐ機能があるのか、何か別の方法があるのか…現在試行錯誤中です。
これが、今回の「悪戦苦闘」内容です。
おわりに
記事を書いていて、
ソース全体を出したほうがよくないか…?
と思い始めました。
GitHubアカウントに、可能なものはどんどん公開していきたいので、興味ある方は言ってください!
大変、励みになります。