[英]How do I pre-load ShellPage during Activation in a WinUI 3 NavigationView Desktop project?
I'd like to pre-load the ShellPage
in a WinUI 3 (v1.1.5) Desktop application.我想在 WinUI 3 (v1.1.5) 桌面应用程序中预加载
ShellPage
。 That is, during Activation
(called by也就是说,在
Activation
期间(由
await App.GetService<IActivationService>().ActivateAsync(args);
in the OnLaunched
handler of the App
class), I'd like to make sure ShellPage
is loaded before any of the navigation pages are displayed.在
App
类的OnLaunched
处理程序中),我想确保在显示任何导航页面之前加载ShellPage
。 I've changed the service configuration to include我已将服务配置更改为包括
services.AddSingleton<ShellPage>();
services.AddSingleton<ShellViewModel>();
in the constructor for the App
class which should mean only one of each of ShellPage
and ShellViewModel
will be instantiated for the app run but the question is when are they fully provisioned?在
App
class 的构造函数中,这应该意味着只有ShellPage
和ShellViewModel
中的一个将为应用程序运行实例化,但问题是它们何时完全配置?
The normal progression is that the Activation
step first assigns ShellPage
to MainWindow.Content
, then navigates to MainPage
(these are the names for the default project).正常的进程是
Activation
步骤首先将ShellPage
分配给MainWindow.Content
,然后导航到MainPage
(这些是默认项目的名称)。 Because MainPage
is actually loaded into a Frame
on ShellPage
, it seems layout for MainPage
happens before ShellPage
layout is completed.因为
MainPage
实际上是加载到ShellPage
上的Frame
中,所以MainPage
的布局似乎发生在ShellPage
布局完成之前。
Any idea how I do this on initial startup?知道我如何在初始启动时执行此操作吗? This is only an issue when the first
Page
is presented.这只是出现第一
Page
时的问题。 After that, ShellPage
is reused.之后,
ShellPage
被重用。
By default, TemplateStudio 's navigation re-instantiates pages for every navigation.默认情况下, TemplateStudio的导航会为每个导航重新实例化页面。 It doesn't use the
ServicesProvider
, so registering your pages as singleton won't help.它不使用
ServicesProvider
,因此将您的页面注册为 singleton 无济于事。
If you want to keep your page instances, you need to set NavigationCacheMode="Required"
on your pages.如果要保留页面实例,则需要在页面上设置
NavigationCacheMode="Required"
。 This way, your pages will be cached even after you navigate away.这样,即使在您离开后,您的页面也会被缓存。
Still, your pages won't be instantiated until you navigate to them once at least.尽管如此,至少在您导航到它们一次之前,您的页面不会被实例化。 In order to instantiate all of your pages at the very beginning, you need to navigate through them at least once.
为了在一开始就实例化所有页面,您需要至少浏览一次。
You can get all the NavigationViewItem
s with a method like this.您可以使用这样的方法获取所有
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;
}
}
}
And use it like this in the NavigationViewService
's Initialize
method.并在
NavigationViewService
的Initialize
方法中像这样使用它。
[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);
}
}
}
A little clarification first, and then the answer I found to the issue.首先澄清一下,然后是我找到的问题的答案。
Andrew's answer (above) is great for instantiating all of the Pages
in the NavigationView
at startup but the very first page loaded still would not have access to a fully loaded ShellPage
in its constructor (and thus, a fully populated element tree). Andrew 的回答(上图)非常适合在启动时实例化
NavigationView
中的所有Pages
,但加载的第一个页面仍然无法访问其构造函数中完全加载的ShellPage
(因此,完全填充的元素树)。 Andrew is right that the NavigationViewItems
( Pages
) don't persist by default, but the ShellPage
does as it's part of the UI. Andrew 是正确的,
NavigationViewItems
( Pages
) 默认情况下不会持久存在,但ShellPage
确实存在,因为它是 UI 的一部分。 Specifically, it is the content of the MainWindow
and defines a Frame
into which NavigationViewItems
are loaded.具体来说,它是
MainWindow
的内容,并定义了一个Frame
, NavigationViewItems
将加载到该框架中。 Regardless of which Page
is displayed, it's the same instance of the ShellPage
people see.无论显示哪个
Page
,人们看到的都是ShellPage
的同一个实例。
The issue arises because of the order in which Activation
(specifically, the DefaultActivationHandler
) is done at App
startup.出现此问题是因为在
App
启动时完成Activation
(特别是DefaultActivationHandler
)的顺序。 When the App
starts, it calls当
App
启动时,它会调用
await App.GetService<IActivationService>().ActivateAsync(args);
which does哪个
// Set the MainWindow Content.
if (App.MainWindow.Content == null)
{
_shell = App.GetService<ShellPage>();
App.MainWindow.Content = _shell ?? new Frame();
}
and navigates to the first Page
(loads the first Page
into the NavigationView.Frame
by calling DefaultActivationHandler
) before finishing the loading of ShellPage
.并在完成
ShellPage
的加载之前导航到第一Page
(通过调用DefaultActivationHandler
将第一Page
加载到NavigationView.Frame
中)。 Thus, ShellPage
is not fully loaded ( ShellPage.IsLoaded == false
) when MainPage
is loaded.因此,加载
MainPage
时, ShellPage
未完全加载 ( ShellPage.IsLoaded == false
)。
To fully instantiate ShellPage
before any of the NavigationViewItem
Pages
are loaded, simply change the loading sequence.要在加载任何
NavigationViewItem
Pages
之前完全实例化ShellPage
,只需更改加载顺序即可。 First, defer the navigation to the first page (whichever you choose) by editing HandleInternalAsync
in DefaultActivationHandler.cs
to首先,通过在
DefaultActivationHandler.cs
中编辑HandleInternalAsync
将导航延迟到第一页(无论您选择哪个)
protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args)
{
//_navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments);
await Task.CompletedTask;
}
Move the navigation to the OnLoaded
handler in ShellPage.xaml.cs
:将导航移动到
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!);
}
All Pages
now receive a loaded ShellPage
when navigated to, regardless of order.现在,无论顺序如何,所有
Pages
在导航到时都会收到加载的ShellPage
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.