アプリ内で画面を遷移させる方法としてアプリにFrameを配置して、その中のPageを遷移させる方法が用意されています。ここではその方法を見ていきましょう。
開発環境
- .NET 6.0
- WinUI 3.0 (Windows App SDK 1.0)
Frameを用いたPageのナビゲーション
アプリにおける画面遷移はFrameの中でPageを遷移させることが基本となります。Frameには画面遷移用のNavigateメソッドが用意されているのに加えて、画面遷移の履歴も保持するので、「戻る」「進む」の操作も可能になります。
また、PageのナビゲーションはNavigationViewなどの他のコントロールでも必要になるので、ぜひここで理解しておきましょう。
ナビゲーションの基本
FrameのNavigateメソッドに遷移させるPageを指定することでナビゲーションを実装することができます。例として、アプリ内のボタンからFrameに表示させるページをPage1 / Page2 / Page3に切り替えるアプリを作成してみましょう。
WinUI3アプリでデフォルトで生成されるMainWindowと、Frame内で遷移させるためのPage (Page1, Page2, Page3)を次のようにコーディングします。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Page1" Click="Button_Click_1"/>
<Button Content="Page2" Click="Button_Click_2"/>
<Button Content="Page3" Click="Button_Click_3"/>
</StackPanel>
<Frame x:Name="contentFrame"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
//Page1へナビゲーションする
private void Button_Click_1(object sender, RoutedEventArgs e)
{
contentFrame.Navigate(typeof(Page1));
}
//Page2へナビゲーションする
private void Button_Click_2(object sender, RoutedEventArgs e)
{
contentFrame.Navigate(typeof(Page2));
}
//Page3へナビゲーションする
private void Button_Click_3(object sender, RoutedEventArgs e)
{
contentFrame.Navigate(typeof(Page3));
}
}
MainWindowにButtonを3つ配置し、その下にFrameを配置します。Buttonをクリックしたときの動作として、FrameのNavigateメソッドでそれぞれPage1, Page2, Page3に遷移するように指定します。その際にNavigateの引数にはtypeof演算子でクラスの型を指定します。
さらにそれぞれのPageは以下のように定義しておきましょう。
Page1
Page1.xaml
<Page ...(略)...>
<StackPanel Height="1000" HorizontalAlignment="Center">
<TextBlock Text="Page 1" FontSize="40"/>
</StackPanel>
</Page>
Page2
Page2.xaml
<Page ...(略)...>
<StackPanel Height="1000" HorizontalAlignment="Center">
<TextBlock Text="Page 2" FontSize="40"/>
</StackPanel>
</Page>
Page3
Page3.xaml
<Page ...(略)...>
<StackPanel Height="1000" HorizontalAlignment="Center">
<TextBlock Text="Page 3" FontSize="40"/>
</StackPanel>
</Page>
これでMainWindow内に配置したFrame内のPageのナビゲーションを行うことができました。
ページ遷移の「戻る」「進む」ボタンを実装する
Frameはナビゲーションの履歴をそれぞれBackStack / ForwardStackに保持しているので、「戻る」「進む」の機能を実装することができます。先ほどのサンプルアプリのMainWindowに以下の部分を追加してみましょう。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="<" Click="Button_Clike_Prev"/>
<Button Content=">" Click="Button_Click_Next"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Page1" Click="Button_Click_1"/>
<Button Content="Page2" Click="Button_Click_2"/>
<Button Content="Page3" Click="Button_Click_3"/>
</StackPanel>
<Frame x:Name="contentFrame"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
...(略)...
//「戻る」ボタンの処理
private void Button_Clike_Prev(object sender, RoutedEventArgs e)
{
if (contentFrame.CanGoBack) contentFrame.GoBack();
}
//「進む」ボタンの処理
private void Button_Click_Next(object sender, RoutedEventArgs e)
{
if (contentFrame.CanGoForward) contentFrame.GoForward();
}
}
MainWindow.xamlでは「戻る」「進む」のボタンを追加しています。MainWindow.xaml.csで先ほど追加した2つのボタンの処理を次のように書いています。
- 「戻る」ボタン:CanGoBackで戻れることを確認して、GoBackメソッドを実行
- 「進む」ボタン:CanGoForwardで進めることを確認して、GoForwardメソッドを実行
ページの状態を保持する
デフォルトではページを遷移するとその内容はすべて初期化されてしまいます。上記の方法で「戻る」「進む」を実装しても、ページの内容までは保持されません。ここでは、以下のようにTextBoxに入力した内容がページ遷移しても保持できるようにしてみましょう。
ページの状態を保持できるようにするためにはPageのNavigationCacheModeをEnabledかRequiredにします。
Page2
Page2.xaml
<Page ...(略)...
NavigationCacheMode="Enabled">
<StackPanel Height="1000" HorizontalAlignment="Center">
<TextBlock Text="Page 2" FontSize="40"/>
</StackPanel>
</Page>
EnabledとRequiredの違いは以下のようになります。
パラメーターを渡してナビゲーションする
Frameを用いてPageを遷移させる際に、Pageにパラメーターを渡すことも可能です。例えばPageにその親要素を渡せば、Pageからその親要素にアクセスすることも可能になります。その場合はNavigateメソッドの第2引数に渡したいパラメーターを指定しましょう。渡されたパラメーターはPageがロードされるときに呼び出されるOnNavigatedToメソッドで受け取ることができます。
ここでは例として、先ほどのアプリの一番上にTextBoxを追加して、Page1を呼び出すとそのTextBoxの文字列をPage1にも表示するようにしてみます。
まず、MainWindowを次のように修正して、TextBoxを追加します。この際、MainWindowに配置するTextBoxはPage1からアクセスできるようにアクセス修飾子をpublicに設定してあります(本来はデータ・バインディングを用いた方がよいと思いますが、ここでは簡単のためにこのようにしています)。
MainWindow
MainWindow.xaml
<Window ...(省略)... >
<StackPanel>
<TextBox x:Name="textBox" x:FieldModifier="public"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="<" Click="Button_Clike_Prev"/>
<Button Content=">" Click="Button_Click_Next"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Page1" Click="Button_Click_1"/>
<Button Content="Page2" Click="Button_Click_2"/>
<Button Content="Page3" Click="Button_Click_3"/>
</StackPanel>
<Frame x:Name="contentFrame"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{
...(略)...
//Page1へナビゲーションする
private void Button_Click_1(object sender, RoutedEventArgs e)
{
contentFrame.Navigate(typeof(Page1), this);
}
...(略)...
}
Navigateメソッドの第2引数にthisとして自分自身を渡すことで、親要素を渡してナビゲーションしています。
続いて、Page1を次のように修正します。
Page1
Page1.xaml
<Page ...(略)...>
<StackPanel Height="1000" HorizontalAlignment="Center">
<TextBlock Text="Page 1" FontSize="40"/>
<TextBlock x:Name="page1_TextBlock" FontSize="30"/>
</StackPanel>
</Page>
Page1.xaml.cs
public sealed partial class Page1 : Page
{
public Page1()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var parent = (MainWindow)e.Parameter;
page1_TextBlock.Text = parent.textBox.Text;
}
}
Pageがロードされると呼び出されるOnNavigatedToメソッドに渡されるNavigationEventArgsのParameterプロパティがナビゲーションで指定したパラメーターになるので、それを受け取ってTextBlockに表示しています。
コメント