もくじ
https://tera1707.com/entry/2022/02/06/144447#winui3
やりたいこと
<NavigationView>
の中に<Frame>
を配置してPage
を表示させて、- NavigationViewの
NavigationViewItem
(メニューの部分)を押したときに画面を遷移させる
ということは、以前の記事でためした。
※メニューの部分とは、下記の部分。
ただ私の場合、NavigationViewのメニューの部分を押してページを遷移させることよりも、 それぞれのページの中のボタンを押したとき等に、お互いのページを行き来させたいということが多い。
例として、下は、以前作ったツールなのだが、
メイン画面の「プリセット」を押すとプリセット選択画面に行き、 プリセット画面の「選択したプリセットを使う」を押すとメイン画面に行く。
https://github.com/tera1707/WindowsMessageSenderWinui
NavigationViewを使わずに、ページ間をお手軽に行き来する処理を実現できないか?調べる。
やったこと
<Frame>
を配置する「メインウインドウ」に、画面遷移をさせるためのpublicなメソッドを設けて、それをグローバル的なWindowクラスのプロパティ経由で、各ページから呼ぶことで実現する。
メインウインドウ
<?xml version="1.0" encoding="utf-8"?> <Window x:Class="NavigationJikken2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:NavigationJikken2" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Frame x:Name="contentFrame" Loaded="contentFrame_Loaded"/> </Window>
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media.Animation; namespace NavigationJikken2 { public sealed partial class MainWindow : Window { // Pageから使うためのウインドウのプロパティ public static MainWindow CurrentWindow { get; private set; } public MainWindow() { this.InitializeComponent(); CurrentWindow = this; } // まずBlankPage1を表示する private void contentFrame_Loaded(object sender, RoutedEventArgs e) { NavigateToBlankPage1(); } // 画面遷移のためのメソッド① public void NavigateToBlankPage1() { contentFrame.Navigate(typeof(BlankPage1), null); } // 画面遷移のためのメソッド② public void NavigateToBlankPage2() { contentFrame.Navigate(typeof(BlankPage2), null, new DrillInNavigationTransitionInfo()); } } }
BlankPage1
<?xml version="1.0" encoding="utf-8"?> <Page x:Class="NavigationJikken2.BlankPage1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:NavigationJikken2" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <TextBlock Text="ここは BlankPage1 です"/> <Button Content="Page2へ行く" Click="Button_Click"/> </StackPanel> </Page>
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; namespace NavigationJikken2 { public sealed partial class BlankPage1 : Page { public BlankPage1() { this.InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { NavigateToBlank2Page(); } private void NavigateToBlank2Page() { MainWindow.CurrentWindow.NavigateToBlankPage2(); } } }
BlankPage2
ほとんどBlankPage1と同じだが、一応。
<?xml version="1.0" encoding="utf-8"?> <Page x:Class="NavigationJikken2.BlankPage2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:NavigationJikken2" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <TextBlock Text="ここは BlankPage2 です"/> <Button Content="Page1に行く" Click="Button_Click"/> </StackPanel> </Page>
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; namespace NavigationJikken2 { public sealed partial class BlankPage2 : Page { public BlankPage2() { this.InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { NavigateToBlank1Page1(); } private void NavigateToBlank1Page1() { MainWindow.CurrentWindow.NavigateToBlankPage1(); } } }
動かした結果
おわりに
今回は、画面遷移処理を持っているWindowのクラスへのグローバル的変数を使ってframe.Navigate()
を呼ぶ、ということをしたが、
とにかく何らかの方法で、frame.Navigate()
を呼んでやればよいと思う。もっとスマートな方法があればよいが、今のところ見つけられていない。
良い方法がありそうなら、コメントください。
備考(以前やってたやり方)
以前同じことを実現しようとしたときに、別の方法で実現していた。
その時のやり方は、Navigate()メソッドの第二引数に、
contentFrame.Navigate(typeof(BlankPage1), null);
画面遷移のためのActionを渡して、それをページ側(👆の例だとBlankPage1
)のOnNavigateTo()
のe.Parameter
で受け取って、それをページ側で呼ぶ、みたいなことをしていた。
(当然複数ページあってそれぞれの間を行き来したいので、List<Action>
を渡して受け取っていた。)
※ここ でやっていたようなこと。
それでも実現はできていたのだが、
- Navigateの第二引数は、本来は遷移元ページから遷移先ページに情報を渡すために使うのに、そこにページ遷移のためのActionとか載せると、本来渡したい情報がなんなのかわかりづらくなり、コードも不自然になる。
- ページが増えるたびにNavigate()の引数を変更しないといけなくなる。
- で、コードがごちゃごちゃする
という感じで、なんとかならないかなーと思っていた。
今回のやり方も、グローバル変数的なもの(staticな、Windowの変数)ができてしまうのがなんかいやなのだが、以前のやり方よりはすっきりするしまぁいいかなー、、という感じ。