如何在 WinUI 3 导航视图桌面项目中激活期间预加载外壳页面?



我想在 WinUI 3 (v1.1.5) 桌面应用程序中预加载ShellPage。也就是说,在Activation期间(由

await App.GetService<IActivationService>().ActivateAsync(args);

App类的OnLaunched处理程序中),我想确保在显示任何导航页面之前加载ShellPage。我已更改服务配置以包括

services.AddSingleton<ShellPage>();
services.AddSingleton<ShellViewModel>();

App类的构造函数中,这应该意味着每个ShellPageShellViewModel中只有一个将为应用运行实例化,但问题是它们何时完全预配?

正常的进展是Activation步骤首先将ShellPage分配给MainWindow.Content,然后导航到MainPage(这些是默认项目的名称)。因为MainPage实际上是在ShellPage上加载到Frame中,所以似乎MainPage的布局发生在布局完成之前ShellPage

知道我在初始启动时是如何做到这一点的吗?这只是呈现第一个Page时的问题。之后,ShellPage被重复使用。

先澄清一下,然后是我找到的问题的答案。

Andrew 的答案(上图)非常适合在启动时实例化NavigationView中的所有Pages,但加载的第一个页面仍然无法访问其构造函数中完全加载的ShellPage(因此,完全填充的元素树)。Andrew 是对的,默认情况下NavigationViewItems(Pages) 不会持久,但ShellPage会保留,因为它是 UI 的一部分。具体来说,它是MainWindow的内容,并定义了加载NavigationViewItemsFrame。无论显示哪个Page,它都是人们看到的ShellPage的相同实例。

出现此问题的原因是Activation(特别是DefaultActivationHandler)在启动时完成App顺序。当App启动时,它会调用

await App.GetService<IActivationService>().ActivateAsync(args);

哪个做

// Set the MainWindow Content.
if (App.MainWindow.Content == null)
{
_shell = App.GetService<ShellPage>();
App.MainWindow.Content = _shell ?? new Frame();
}

并在完成ShellPage加载之前导航到第一个Page(通过调用DefaultActivationHandler将第一个Page加载到NavigationView.Frame中)。因此,当ShellPage加载时MainPage没有完全加载(ShellPage.IsLoaded == false)。

要在加载任何NavigationViewItemPages之前完全实例化ShellPage,只需更改加载顺序即可。首先,通过将HandleInternalAsync编辑到DefaultActivationHandler.cs

protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args)
{
//_navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments);
await Task.CompletedTask;
}

将导航移动到ShellPage.xaml.cs中的OnLoaded处理程序:

private void OnLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
TitleBarHelper.UpdateTitleBar(RequestedTheme);
KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu));
KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.GoBack));
App.GetService<INavigationService>().NavigateTo(typeof(MainViewModel).FullName!);
}

现在,无论顺序如何,所有Pages在导航到时都会收到已加载ShellPage

默认情况下,TemplateStudio的导航会为每个导航重新实例化页面。它不使用ServicesProvider,因此将您的页面注册为单例将无济于事。

如果要保留页面实例,则需要在页面上设置NavigationCacheMode="Required"。这样,即使您离开,您的页面也会被缓存。

不过,您的页面至少在您导航到它们一次之前不会被实例化。为了在一开始就实例化所有页面,您需要至少浏览一次。

您可以使用这样的方法获得所有NavigationViewItem

private static IEnumerable<NavigationViewItem> GetNavigationViewItems(IEnumerable<object> items)
{
foreach (var item in items.OfType<NavigationViewItem>())
{
yield return item;
foreach (var grandChild in GetNavigationViewItems(item.MenuItems.OfType<NavigationViewItem>()))
{
yield return grandChild;
}
}
}

并在NavigationViewServiceInitialize方法中像这样使用它。

[MemberNotNull(nameof(_navigationView))]
public void Initialize(NavigationView navigationView)
{
_navigationView = navigationView;
_navigationView.BackRequested += OnBackRequested;
_navigationView.ItemInvoked += OnItemInvoked;
IEnumerable<NavigationViewItem> menuItems = 
GetNavigationViewItems(_navigationView.MenuItems);
foreach (var item in menuItems)
{
if (item.GetValue(NavigationHelper.NavigateToProperty) is string pageKey)
{
_navigationService.NavigateTo(pageKey);
}
}
}

相关内容

  • 没有找到相关文章

最新更新