Unreliable navigation to root page

March 26th 2021 Xamarin

Xamarin.Forms Shell navigation seems well documented but either I don't understand the documentation correctly or it isn't accurate.

The part that confuses me is the description of the following two route formats:

//route - The route hierarchy will be searched for the specified route, upwards from the current position. The matching page will replace the navigation stack.

///route - The route hierarchy will be searched for the specified route, downwards from the current position. The matching page will replace the navigation stack.

First of all, I don't understand the difference between the two. They both seem to always work identically for me. But leaving that aside, the documentation clearly states that the requested page will fully replace the navigation stack. But even that doesn't always happen.

I encountered a reproducible scenario in which the following call doesn't open the requested page:

await Shell.Current.GoToAsync($"//{nameof(ItemsPage)}");

The requested ItemsPage is still the root of the new navigation stack. But on top of it, an instance of ItemDetailPage is already opened. How can this be reproduced? By following these steps in a newly created project from the Xamarin.Forms Flyout template:

  1. Open the ItemsPage from the flyout menu.
  2. Navigate to the ItemDetailPage which opens on top of the ItemsPage on the same navigation stack.
  3. Open the AboutPage from the flyout menu. This switches to a new navigation stack with this page as the only one opened.
  4. Open the ItemsPage from the flyout menu. This will switch to the previous navigation stack with both the ItemsPage and the ItemDetailPage still opened.

While this could be intentional behavior, I don't think it matches the documentation (as quoted above). It also interfered with the way I wanted navigation to work in my application. Fortunately, I found a workaround with which I could reliably achieve that after following the steps above the ItemsPage would be the only one opened on its own navigation stack.

For that to work, I had to navigate to the root of the navigation stack before switching to the other navigation stack at step 3 above using the following code:

await Shell.Current.GoToAsync($"///{nameof(ItemsPage)}", false);
await Shell.Current.GoToAsync($"///{nameof(AboutPage)}");

The first call navigates back to the root of the navigation stack if there are any other pages open on top of it (ItemDetailPage in my case). Its second parameter disables the navigation animation. The second call then navigates to the page we actually want to open.

To try the described behavior yourself, check my GitHub repository. It's a slightly modified project created from the Xamarin.Forms Flyout template with buttons which make it easy to follow both the steps reproducing the issue and the fix for the issue.

Based on my experience, Xamarin.Forms Shell navigation doesn't always work as documented (or at least not as I understand it). In this blog post I described a workaround for the unexpected behavior I encountered in my application. At least in my case it worked great.

Get notified when a new blog post is published (usually every Friday):

If you're looking for online one-on-one mentorship on a related topic, you can find me on Codementor.
If you need a team of experienced software engineers to help you with a project, contact us at Razum.
Creative Commons License