Search code examples
c#windowsuwpsplitview

[UWP][C#] Override backpress Navigation set in Appx.cs


A bit stuck here. I have a splitview app that has the event for backward navigation when the backkey is pressed residing in Appx.cs.

I want to define a different action in one of the pages navigated inside the splitviews content page (for example, when a certain element is visible to dismiss the element) however the app always follows the event set in appx.cs, and ignores the event in the page that is loaded in the content frame. Here is the code in appx.cs:

protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (Window.Current.Content == null)
    {
        // Create a Frame to act as the navigation context and navigate to the first page
        _rootFrame = new Frame();
        _rootFrame.NavigationFailed += OnNavigationFailed;
        _rootFrame.Navigated += OnNavigated;

        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            //TODO: Load state from previously suspended application
        }

        // Place the frame in the current Window
        Window.Current.Content = new MainPage(_rootFrame);

        // Register a handler for BackRequested events and set the
        // visibility of the Back button
        SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;

        SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
            _rootFrame.CanGoBack ?
            AppViewBackButtonVisibility.Visible :
            AppViewBackButtonVisibility.Collapsed;
    }
}

private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
    if (_rootFrame != null && _rootFrame.CanGoBack)
    {
        e.Handled = true;
        _rootFrame.GoBack();

    }
}

And here is the code in one of the pages that is loaded into the splitviews content pane:

public CalcOutputPage()
{
    this.InitializeComponent();


    // add page specific handling of back navigation when entering this page
    SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}

// page specific back button navigation
private void OnBackRequested(object sender, BackRequestedEventArgs e)
{

    if (MobileStackPanel.Visibility == Visibility.Visible)
    {
       MobileStackPanel.Visibility = Visibility.Collapsed;
        e.Handled = true;
    }
    else
    {
        e.Handled = false;
    }
}

But this isn't working. It works if its the first page loaded in the navigation stack, but at all other times, the app follows the navigation instructions in appx.cs

So to clarify:

  • the OnBackRequested method in Appx.cs is handling the back navigation in my app.
  • I have a page (lets call it PageTwo.xaml) open in the splitview content pane.
  • in PageTwo.xaml, I want to have an event for when OnBackRequested is pressed
  • I cant at the moment, as the one in Appx.cs is the one that is always called
  • i would like to know if there is a way to have the OnBackRequested in the PageTwo.xaml.cs page fire, instead of the OnBackRequested in the Appx.cs Page.

Any help would be appreciated. I'm losing my mind trying to get this working :P


Solution

  • Event handlers are triggered in the same order they have been added, so no luck on this side. One alternative is to make your own event, wrapping the original one. In App.xaml.cs:

    public event EventHandler<BackRequestedEventArgs> BackRequested;
    
    private void OnBackRequested(object sender, BackRequestedEventArgs e)
    {
        // Raise child event
        var eventHandler = this.BackRequested;
    
        if (eventHandler != null)
        {
            eventHandler(sender, e);
        }
    
        if (!e.Handled)
        {
            if (_rootFrame != null && _rootFrame.CanGoBack)
            {
                e.Handled = true;
                _rootFrame.GoBack();
    
            }
        }
    }
    

    Then in your page, subscribe to the child event instead of the main one:

    ((App)(App.Current)).BackRequested += OnBackRequested;
    

    Make sure to unsubscribe to the event when leaving the page, or you may end up with a memory leak.