I'd like to pre-load the ShellPage
in a WinUI 3 (v1.1.5) Desktop application. That is, during Activation
(called by
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. 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?
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). Because MainPage
is actually loaded into a Frame
on ShellPage
, it seems layout for MainPage
happens before ShellPage
layout is completed.
Any idea how I do this on initial startup? This is only an issue when the first Page
is presented. After that, ShellPage
is reused.
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 is right that the NavigationViewItems
(Pages
) don't persist by default, but the ShellPage
does as it's part of the UI. Specifically, it is the content of the MainWindow
and defines a Frame
into which NavigationViewItems
are loaded. Regardless of which Page
is displayed, it's the same instance of the ShellPage
people see.
The issue arises because of the order in which Activation
(specifically, the DefaultActivationHandler
) is done at App
startup. When the App
starts, it calls
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
. Thus, ShellPage
is not fully loaded (ShellPage.IsLoaded == false
) when MainPage
is loaded.
To fully instantiate ShellPage
before any of the NavigationViewItem
Pages
are loaded, simply change the loading sequence. First, defer the navigation to the first page (whichever you choose) by editing HandleInternalAsync
in DefaultActivationHandler.cs
to
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
:
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.