WinUI 3.0 Desktop C# 如何导航到已存在Page实例并保留页面状态
我正在使用微软推出的新一代UI技术WinUI 3进行桌面开发。
我的问题与Stack Overflow上的「WinUI 3.0 Desktop - C# Page Navigation」提问类似,但我具体想要了解如何导航到已存在的Page实例,而非每次跳转都创建新实例。
我应用的主菜单使用NavigationView控件实现。
备注:我安装了xaml-controls-gallery示例解决方案来学习WinUI 3的基础概念。
目前我在NavigationView中添加了3个NavigationViewItem实例,XAML代码如下:
<NavigationView x:Name="navigationView" PaneDisplayMode="Top" SelectionFollowsFocus="Enabled" IsBackButtonVisible="Collapsed" ItemInvoked="NavigationView_OnItemInvoked" > <NavigationView.MenuItems> <NavigationViewItem Icon="Play" Content="Menu 1" x:Name="Menu1Item" Tag="Page1" /> <NavigationViewItem Icon="Filter" Content="Menu 2" x:Name="Menu2Item" Tag="Page2"/> <NavigationViewItem Icon="Refresh" Content="Menu 3" x:Name="Menu3Item" Tag="Page3" /> </NavigationView.MenuItems> <!-- 选中导航项对应的内容会展示在这个区域 --> <Grid Padding="20"> <Frame x:Name="rootFrame" Navigated="RootFrame_OnNavigated"/> </Grid> </NavigationView>
每个菜单项对应的内容需要展示在名为rootFrame的Frame控件中,我已经为内容创建了三个Page类:Page1、Page2、Page3。
在后置代码中,我处理了NavigationView的ItemInvoked事件,通过判断被点击导航项的Tag获取对应Page类型,再调用导航方法,代码如下:
private void NavigationView_OnItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args) { FrameNavigationOptions navOptions = new FrameNavigationOptions(); navOptions.TransitionInfoOverride = args.RecommendedNavigationTransitionInfo; string navItemTag = args.InvokedItemContainer.Tag.ToString(); Type pageType = null; if (navItemTag == "Page1") { pageType = typeof(Page1); } else if (navItemTag == "Page2") { pageType = typeof(Page2); } else if (navItemTag == "Page3") { pageType = typeof(Page3); } if (pageType == null) { return; } rootFrame.NavigateToType(pageType, null, navOptions); }
但问题在于,对Frame实例调用NavigateToType每次都会创建新的Page类实例,会丢失用户修改过的页面状态,还会重复执行耗时的数据加载操作。我希望可以导航到已经存在的Page实例,保留原有状态。
目前我还没有找到实现方案,由此带来的现象是:在Page的OnNavigatedTo事件中,参数e的NavigationMode属性始终为NavigationMode.New,而不是我期望的NavigationMode.Refresh,以Page1为例:
public sealed partial class Page1 : Page { public Page1() { this.InitializeComponent(); ViewModel = new Page1ViewModel(); // 加载数据(耗时操作) } public Page1ViewModel ViewModel { get; set; } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); // e.NavigationMode始终为NavigationMode.New // 如何才能得到NavigationMode.Refresh? } }
请问有人知道如何实现导航到已存在的Page实例吗?
我尝试过的 workaround 是直接替换Frame的Content:
rootFrame.Content = instanceOfPage;
但我不想使用这个方案,因为它绕过了Frame的原生导航逻辑,也无法触发跳转时的过渡动画。
我了解到WPF和旧版.NET Framework中有NavigationWindow类可以实现该需求,但WinUI中暂时还没有这个类,请问WinUI 3中有没有正规的实现方案?
内容的提问来源于stack exchange,提问作者Martin

