How to intercept Navigation Bar Back Button Clicked in Xamarin Forms?

Amrut picture Amrut · Jul 29, 2015 · Viewed 17.1k times · Source

I have a xamarin form page where a user can update some data in a form. I need to intercept the Navigation Bar Back Button Clicked to warn the user if some data have not been saved.How to do it?

I'm able to intercept the hardware Bar Back Button Clicked in Android using the Android.MainActivity.OnBackPressed(), but that event is raised only on hardware Bar Back Button Clicked, not on Navigation Bar Back Button Clicked.

I tried also to override Xamarin.Forms.NavigationPageOnBackButtonPressed() but it doesn't work. Why? Any one have already solved that issue?

I also tried by overriding OnDisappear(), there are two problems:

  1. The page has already visually disappeared so the "Are you sure?" dialog appears over the previous page.
  2. Cannot cancel the back action.

So, is it possible to intercept the navigation bar back button press?

Answer

barry picture barry · Jul 31, 2015

I was able to show a confirmation dialog that could cancel navigation by overriding the following methods in the FormsApplicationActivity.

  // navigation back button
  public override bool OnOptionsItemSelected(IMenuItem item)
  {
     if (item.ItemId == 16908332)
     {
        var currentViewModel = (IViewModel)navigator.CurrentPage.BindingContext;
        currentViewModel.CanNavigateFromAsync().ContinueWith(t =>
        {
           if (t.Result)
           {
              navigator.PopAsync();
           }
        }, TaskScheduler.FromCurrentSynchronizationContext());
        return false;
     }
     else
     {
        return base.OnOptionsItemSelected(item);
     }
  }

  // hardware back button
  public async override void OnBackPressed()
  {
     var currentViewModel = (IViewModel)navigator.CurrentPage.BindingContext;

     // could display a confirmation dialog (ex: "Cancel changes?")
     var canNavigate = await currentViewModel.CanNavigateFromAsync();
     if (canNavigate)
     {
        base.OnBackPressed();
     }
  }

The navigator.CurrentPage is a wrapper around the INavigation service. I do not have to cancel navigation from modal pages so I am only handling the NavigationStack.

this.navigation.NavigationStack[this.navigation.NavigationStack.Count - 1];