May 13th, 2020

Xamarin.Forms Shell Quick Tip – Passing Data When Navigating

James Montemagno
Principal Manager, Tech PM

Every mobile application needs navigation. Xamarin.Forms Shell offers built-in route based navigation to enable easy navigation to and from pages in your application. Additionally, since it is based on a route schema, you can navigate using absolute or relative routes that will even inflate a full back stack. In most cases, relative route navigation is best as you are pushing a unique page onto the stack. Let’s say you are on a monkeys page and wanted to navigate to the details. You would use a simple relative route to navigate: await Shell.Current.GoToAsync(“monkeydetails”);

2 screens from an app showing navigation from the root to details page Now, to build up a navigation stack for deep linking you can use absolute routes. This will take you to the monkeys route and then push the details page. await Shell.Current.GoToAsync(“//monkeys/details”); This is helpful. However, in both cases it would be great is if you could pass in data to the details page to tell it to display specific monkeys details. Read on for a full walkthrough of how to pass data from one page to another.

Passing dData What happens when you want to pass data from one page to another? Well that is where Shell’s built in

Query Parameters come in. It enables you to seamlessly pass data around your application. Let’s walk through a simple app that increase the count on the page and passes that data to the next page when the app navigates: Image Pass Data with Shell Query Parameter Look at the code to setup the first page. It is a relatively simple user interface with a few buttons and label to display the count: In the code behind for the page when we click the button, it increase the count and notifies the user interface.

public int Count { get; set; }

void ButtonClick_Clicked(object sender, EventArgs e)
{
    Count++;
    OnPropertyChanged(nameof(Count));
}

Navigating To Page2 Now, let’s say that we want to navigate to the second page, in this case

Page2. We would first register our route in our Shell: Routing.RegisterRoute(nameof(Page2), typeof(Page2)); Then we can navigate to it using

GoToAsync on the current Shell. await Shell.Current.GoToAsync(nameof(Page2)); We want to pass the current count, so we will use a query parameter on our path. This follows standard Uri routes such as

path?param1=hello&param2=world. So, to pass the count we will navigate passing a parameter named count. Any data that is passed is automatically encoded for you. async void ButtonNavigate_Clicked(object sender, EventArgs e) { await Shell.Current.GoToAsync($”{nameof(Page2)}?Count={Count}”); }

Parsing Parameters Now that we have passed the count using the parameter, we must receive it on the second page. You can do this either in the code behind of the page that you are navigating to, or to the

BindingContext of the page such as a view model. The first thing to do is to add a public property that Xamarin.Forms Shell will call the set on. Here, we will create another Count property that is a string and when we set the value we will call UnescapeDataString as a best practice. string count = “”; public string Count { get => count; set { count = Uri.UnescapeDataString(value ?? string.Empty); OnPropertyChanged(); } } Lastly, add a

QueryProperty that tells Xamarin.Forms Shell the property to set the parameter name to parse. Here, we will set the Count property for the count parameter that we passed. [QueryProperty(nameof(Count), nameof(Count))] public partial class Page2 : ContentPage { //… } In this example, we only passed one parameter. However, you can add as many

QueryProperty attributes to the top of your class as you would like.

Deep Linking Combining route based navigation with query properties can be extremely powerful when creating apps that deep link from the web or custom data schemes. For example in the application

Island Tracker, a custom data scheme is used to create a link that the app can use to send friend requests. Here is an example of the deep link that a user would click: acislandtracker://friends/invite?id=a3be899c-41df-4ce6-8ca7-26b0642efcde&name=James When it is clicked, Xamarin.Forms will activate the app using the

AppLink API. protected override async void OnAppLinkRequestReceived(Uri uri) { await Shell.Current.GoToAsync($”//{uri.Host}/{uri.PathAndQuery}”); } From there, Shell will ensure the

friend page is navigated to and then it will navigate to the invite page. If navigation to the friend page first was not the intent, simply pass in the full uri to Shell. It takes care of the rest to open the invite page. Image Deep Link into iOS Application with Query Property

Learn More To learn more about navigation with Xamarin.Forms Shell and more information about using

QueryProperty attributes, browse through our full documentation on Shell navigation. You can also grab the source code for this sample on GitHub. Want more Xamarin.Forms? Checkout our Xamarin.Forms 101 series on Channel 9.

Author

James Montemagno
Principal Manager, Tech PM

James Montemagno is a Principal Lead Program Manager for Developer Community at Microsoft. He has been a .NET developer since 2005, working in a wide range of industries including game development, printer software, and web services. Prior to becoming a Principal Program Manager, James was a professional mobile developer and has now been crafting apps since 2011 with Xamarin. In his spare time, he is most likely cycling around Seattle or guzzling gallons of coffee at a local coffee shop. He ...

More about author

7 comments

Discussion is closed. Login to edit/delete existing comments.

  • David Allen

    Currently there is a limitation on the overall size of the uri that can be used for navigation (I believe its a 2048 character limit). This limits the size of objects you can serialize and send via the query (if the overall uri size to too large, the data passed in the query is truncated and cant be deserialized).

    There are various approaches you can use to get around this. You could push a page using...

    Read more
  • Michael Lopez

    Looks like using the query parameter is good for passing a simple string but I don’t see how it can be used to pass a Model object. For that shouldn’t we continue to use what we’ve always used, namely (and as Rikudou referred to) Navigation.PushAsync(new Pagename(object)); ?

    • Michael Lopez

      I’m answering my own question: The Shell template app uses Navigation.PushAsync(new Pagename(object));

  • Shaun Pryszlak

    Doesn’t this sort of negate view models and dependency injection, and all those good practices you have been preaching all these years? Can you mix and match the two? And isn’t it a bit of a kicker that you still have to unescape the strings?

    • David Allen

      I agree. We have used an injected NavigationManager service to abstract the navigation, provide easier access to this like current/previous page, current and previous navigation stack, and improve data passing, which also allows us to maintain the MVVM framework.

      It's early days with Shell, but I'm not currently a fan of the approach and I think its really a solution looking for a problem. Maybe if it adds in things like Tab Templates, full NavBar templates,...

      Read more
    • Michael Lopez

      I had the same thought.

  • Rikudou En Sof

    Reminds me of the
    Navigation.PushAsync(new Pagename(object));