Xamarin.Forms Shell Quick Tip – Passing Data When Navigating

James Montemagno

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));
}

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.

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.

7 comments

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

  • Rikudou En Sof 0

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

  • Shaun Pryszlak 0

    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?

    • Michael Lopez 0

      I had the same thought.

    • David Allen 0

      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, better flyout menu content support (dynamic menu content and collapsible items for example), and more page transition animations, so it makes those things easy for developers then it will justify its use, but currently I would not recommend it (our client that used it specified it’s use after strong recommendations from Microsoft/Xamarin)

  • Michael Lopez 0

    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 0

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

  • David Allen 0

    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 the INavigation object as previously mentioned (Navigation.PushAsync(new Pagename(object))) or to retain the uri navigation use a reference to a place where the data is stored (whether an in memory object or persistent storage).

    In a recent project for a client we created a NavigationManager service that implemented an interface so it could be injected, which abstracted the uri navigation process and provided write/read data methods that could store the passed data in the service and retain uri navigation. The use of an injected service, also allowed us to retain good MVVM practices.

Feedback usabilla icon