Search code examples
c#uwptemplate10

How to open a secondary window with a shell?


I tried to adapt the instructions for implementing a shell in Template10 on GitHub to a shell in a secondary window, but it is not working.

This code:

await DispatcherWrapper.Current().DispatchAsync(async () =>
        {
                //The next line gets the exception
                var control = await BootStrapper.Current.NavigationService.OpenAsync(
                                                    typeof(MySecondaryShell), null, "My Secondary Function");
                control.Released += Control_Released;
                BootStrapper.Current.NavigationService.Navigate(typeof(MySecondaryPage));
    });

gets this exception:

E VUI 1808 16:12:27.203 D:\SVN_Trunk\Source\Uwp\Gui\UwpMain\ViewModels\MyPrimaryShellViewModel.cs.275.MyFunction System.NullReferenceException: Object reference not set to an instance of an object. at Uwp.Main.UwpMain_XamlTypeInfo.XamlUserType.ActivateInstance() at Windows.UI.Xaml.Controls.Frame.Navigate(Type sourcePageType, Object parameter, NavigationTransitionInfo infoOverride) at Template10.Services.NavigationService.FrameFacade.Navigate(Type page, Object parameter, NavigationTransitionInfo infoOverride) at Template10.Services.NavigationService.NavigationService.d__34.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Template10.Services.NavigationService.NavigationService.Navigate(Type page, Object parameter, NavigationTransitionInfo infoOverride) at Template10.Services.ViewService.ViewService.<>c__DisplayClass1_0.<b__0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Template10.Services.ViewService.ViewService.d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at Uwp.Main.ViewModels.MyPrimaryShellViewModel.<>c__DisplayClass63_0.<b__0>d.MoveNext()

MySecondaryShell is constructed like this:

public static HamburgerMenu HamburgerMenu => Instance.EmulatorHamburgerMenu;

    public MySecondaryShell(INavigationService navigationService)
    {
        this.InitializeComponent();
        HamburgerMenu.NavigationService = navigationService;
    }

When I open the primary window with its shell, I create the shell object and then assign the NavigationService to it.

But when I'm opening a secondary window, I just call NavigationService.OpenAsync with the typeof(MySecondaryShell) as a parameter. Is the problem that the NavigationService is not set correctly in the shell? (From reading the Template10 code in my last question, I could not see where the NavigationService is set).

How should I open a shell as a secondary window?


Solution

  • How should I open a shell as a secondary window?

    The problem is you have not passed navigationService to MySecondaryShell. And then MySecondaryShell will fail initialization without navigationService. You could make your shell like following.

    public sealed partial class MyShell : Page
    {
        public static MyShell Instance { get; set; }
    
        public static HamburgerMenu HamburgerMenu => Instance.MyHamburgerMenu;
    
        Services.SettingsServices.SettingsService _settings;
        public MyShell()
        {
            Instance = this;
            this.InitializeComponent();
            _settings = Services.SettingsServices.SettingsService.Instance;
            var service = BootStrapper.Current.NavigationServiceFactory(BootStrapper.BackButton.Attach, BootStrapper.ExistingContent.Exclude);          
            SetNavigationService(service);
    
        }  
        public void SetNavigationService(INavigationService navigationService)
        {
            MyHamburgerMenu.NavigationService = navigationService;
            HamburgerMenu.RefreshStyles(_settings.AppTheme, true);
            HamburgerMenu.IsFullScreen = _settings.IsFullScreen;
            HamburgerMenu.HamburgerButtonVisibility = _settings.ShowHamburgerButton ? Visibility.Visible : Visibility.Collapsed;
        }
    }
    

    Usage

    await DispatcherWrapper.Current().DispatchAsync(async () =>
    {
        var control = await BootStrapper.Current.NavigationService.OpenAsync(typeof(Views.MyShell), null, Guid.NewGuid().ToString());
        await control.CoreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            Views.MyShell.HamburgerMenu.NavigationService.Navigate(typeof(Views.TestPage));
        });
    
    });