webviewuwpback-buttonback-button-control

BackRequested is triggering more than once in UWP app


I have an app in which i mainly have a webview. i am having a problem. i have made the back button to goto previous webpage of webview it works fine and when it has no previous pages it quits with a MessageBox(Popup). The problem is when i navigate another page and press back it recursively triggers back button event and shows the MessageBox

 Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += (s, e) =>
        {
            e.Handled = true;
            if (Web_view.CanGoBack)
            {
                Web_view.GoBack();
                e.Handled = true;
            }
           else
            {
                quit();
                e.Handled = true;
            }
        };

The above is code of my main page

 private async void quit()
    {
        MessageDialog msg = new MessageDialog("Do you really want to quit?", "Quit");
        msg.Commands.Add(new UICommand("Yes") { Id = 0 });
        msg.Commands.Add(new UICommand("No") { Id = 1 });
        var ans = await msg.ShowAsync();
        if(ans.Id.Equals(0))
        {
            //System.Diagnostics.Debug.WriteLine("Exit");
            App.Current.Exit();
        }
    }

this is the code of quit function. I am navigating to another page from this using code

 private void about_Click(object sender, RoutedEventArgs e)
    {
        Frame.Navigate(typeof(BlankPage1));
    }

And the backRequested code of blanckPage1 is

 SystemNavigationManager.GetForCurrentView().BackRequested += (s,e)=>
        {
            e.Handled = true;
           // Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested -= BlankPage1_BackRequested;
           //System.Diagnostics.Debug.WriteLine("BackRequested");
            if (Frame.CanGoBack)
            {
                e.Handled = true;
                Frame.GoBack();
            }
            else
            {
                e.Handled = true;
            }
        };

To make it more clear for example when i open the app the webview navigates to www.example.com then following the links there i will get to some other page(for example www.example.com/link/firstlink). then i will navigate my frame to blankpage1 and from there i will press back. then insted of coming back to previous page (www.example.com/link/firstlink) it comes to beginning page (www.example.com) and shows the quit popup how can i fix this?

Thank you for all your replay.


Solution

  • Your problem is that you are still keeping the event handler: In your code when navigating back from BlankPage1, both .BackRequested handlers are called. You would need to deregister from .BackRequested on MainPage when leaving it, for example like this:

    MainPage:

    protected override void OnNavigatedTo(NavigationEventArgs e) {
        SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
    }
    
    protected override void OnNavigatedFrom(NavigationEventArgs e) {
        SystemNavigationManager.GetForCurrentView().BackRequested -= OnBackRequested;
    }
    
    private void OnBackRequested(object sender, BackRequestedEventArgs e) {
        // Your code to navigate back
        if (Web_view.CanGoBack)
        {
            Web_view.GoBack();
            e.Handled = true;
        }
        else
        {
            quit();
            e.Handled = true;
        }
    }
    

    And the same on BlankPage1... Though it would be far easier to register to BackRequested in your App.xaml.cs where you would handle your (Window.Current.Content as Frame) for the whole app, something like this. To make it "nice" code also with an interface:

    INavigationPage:

    public interface INavigationPage {
        // When overriding the method returns true or false if the Page handled back request
        bool HandleBackRequested();
    }
    

    App.xaml.cs:

    // ... Code before
    protected override void OnLaunched(LaunchActivatedEventArgs e) {
        SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
    }
    
    private void OnBackRequested(object sender, BackRequestedEventArgs e) {
        Frame frame = Window.Current.Content as Frame;
        if (frame == null) return;
    
        INavigationPage page = frame.Content as INavigationPage;
        if (page == null) return;
    
        // Ask if the page handles the back request
        if (page.HandleBackRequested()) {
            e.Handled = true;
        // If not, go back in frame
        } else if (frame.CanGoBack) {
            e.Handled = true;
            frame.GoBack();
        }
    }
    // ... Code after
    

    MainPage.xaml.cs:

    ... class MainPage : Page, INavigationPage {
        // ... Code before
    
        // Implement the interface handling the backRequest here if possible
        public bool HandleBackRequested() {
            if (Web_view.CanGoBack) {
                Web_view.GoBack();
                return true;
            }
            return false;
        }
    
        // ... Code after
    }
    

    Then the BlankPage does not require any code and no subscribing to .BackRequested.