Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft EdgeMore info about Internet Explorer and Microsoft Edge
Table of contentsExit focus mode

.NET MAUI Shell navigation

  • 2025-01-14
Feedback

In this article

Browse sample. Browse the sample

.NET Multi-platform App UI (.NET MAUI) Shell includes a URI-based navigation experience that uses routes to navigate to any page in the app, without having to follow a set navigation hierarchy. In addition, it also provides the ability to navigate backwards without having to visit all of the pages on the navigation stack.

TheShell class defines the following navigation-related properties:

  • BackButtonBehavior, of typeBackButtonBehavior, an attached property that defines the behavior of the back button.
  • CurrentItem, of typeShellItem, the currently selected item.
  • CurrentPage, of typePage, the currently presented page.
  • CurrentState, of typeShellNavigationState, the current navigation state of theShell.
  • Current, of typeShell, which provides access to the current Shell.

TheBackButtonBehavior,CurrentItem, andCurrentState properties are backed byBindableProperty objects, which means that these properties can be targets of data bindings.

Navigation is performed by invoking theGoToAsync method, from theShell class. When navigation is about to be performed, theNavigating event is fired, and theNavigated event is fired when navigation completes.

Note

Navigation can still be performed between pages in a Shell app by using theNavigation property. For more information, seePerform modeless navigation.

Routes

Navigation is performed in a Shell app by specifying a URI to navigate to. Navigation URIs can have three components:

  • Aroute, which defines the path to content that exists as part of the Shell visual hierarchy.
  • Apage. Pages that don't exist in the Shell visual hierarchy can be pushed onto the navigation stack from anywhere within a Shell app. For example, a details page won't be defined in the Shell visual hierarchy, but can be pushed onto the navigation stack as required.
  • One or morequery parameters. Query parameters are parameters that can be passed to the destination page while navigating.

When a navigation URI includes all three components, the structure is: //route/page?queryParameters

Register routes

Routes can be defined onFlyoutItem,TabBar,Tab, andShellContent objects, through theirRoute properties:

<Shell ...>    <FlyoutItem ...                Route="animals">        <Tab ...             Route="domestic">            <ShellContent ...                          Route="cats" />            <ShellContent ...                          Route="dogs" />        </Tab>        <ShellContent ...                      Route="monkeys" />        <ShellContent ...                      Route="elephants" />          <ShellContent ...                      Route="bears" />    </FlyoutItem>    <ShellContent ...                  Route="about" />                      ...</Shell>

Note

All items in the Shell hierarchy have a route associated with them. If you don't set a route, one is generated at runtime. However, generated routes are not guaranteed to be consistent across different app sessions.

The above example creates the following route hierarchy, which can be used in programmatic navigation:

animals  domestic    cats    dogs  monkeys  elephants  bearsabout

To navigate to theShellContent object for thedogs route, the absolute route URI is//animals/domestic/dogs. Similarly, to navigate to theShellContent object for theabout route, the absolute route URI is//about.

Warning

AnArgumentException will be thrown on app startup if a duplicate route is detected. This exception will also be thrown if two or more routes at the same level in the hierarchy share a route name.

Register detail page routes

In theShell subclass constructor, or any other location that runs before a route is invoked, additional routes can be explicitly registered for any detail pages that aren't represented in the Shell visual hierarchy. This is accomplished with theRouting.RegisterRoute method:

Routing.RegisterRoute("monkeydetails", typeof(MonkeyDetailPage));Routing.RegisterRoute("beardetails", typeof(BearDetailPage));Routing.RegisterRoute("catdetails", typeof(CatDetailPage));Routing.RegisterRoute("dogdetails", typeof(DogDetailPage));Routing.RegisterRoute("elephantdetails", typeof(ElephantDetailPage));

This example registers detail pages, that aren't defined in theShell subclass, as routes. These detail pages can then be navigated to using URI-based navigation, from anywhere within the app. The routes for such pages are known asglobal routes.

Warning

AnArgumentException will be thrown if theRouting.RegisterRoute method attempts to register the same route to two or more different types.

Alternatively, pages can be registered at different route hierarchies if required:

Routing.RegisterRoute("monkeys/details", typeof(MonkeyDetailPage));Routing.RegisterRoute("bears/details", typeof(BearDetailPage));Routing.RegisterRoute("cats/details", typeof(CatDetailPage));Routing.RegisterRoute("dogs/details", typeof(DogDetailPage));Routing.RegisterRoute("elephants/details", typeof(ElephantDetailPage));

This example enables contextual page navigation, where navigating to thedetails route from the page for themonkeys route displays theMonkeyDetailPage. Similarly, navigating to thedetails route from the page for theelephants route displays theElephantDetailPage. For more information, seeContextual navigation.

Note

Pages whose routes have been registered with theRouting.RegisterRoute method can be deregistered with theRouting.UnRegisterRoute method, if required.

Perform navigation

To perform navigation, a reference to theShell subclass must first be obtained. This reference can be obtained through theShell.Current property. Navigation can then be performed by calling theGoToAsync method on theShell object. This method navigates to aShellNavigationState and returns aTask that will complete once the navigation animation has completed. TheShellNavigationState object is constructed by theGoToAsync method, from astring, or aUri, and it has itsLocation property set to thestring orUri argument.

Important

When a route from the Shell visual hierarchy is navigated to, a navigation stack isn't created. However, when a page that's not in the Shell visual hierarchy is navigated to, a navigation stack is created.

The current navigation state of theShell object can be retrieved through theShell.Current.CurrentState property, which includes the URI of the displayed route in theLocation property.

Absolute routes

Navigation can be performed by specifying a valid absolute URI as an argument to theGoToAsync method:

await Shell.Current.GoToAsync("//animals/monkeys");

This example navigates to the page for themonkeys route, with the route being defined on aShellContent object. TheShellContent object that represents themonkeys route is a child of aFlyoutItem object, whose route isanimals.

Warning

Absolute routes don't work with pages that are registered with theRouting.RegisterRoute method.

Relative routes

Navigation can also be performed by specifying a valid relative URI as an argument to theGoToAsync method. The routing system will attempt to match the URI to aShellContent object. Therefore, if all the routes in an app are unique, navigation can be performed by only specifying the unique route name as a relative URI.

The following example navigates to the page for themonkeydetails route:

await Shell.Current.GoToAsync("monkeydetails");

In this example, themonkeyDetails route is searched for until the matching page is found. When the page is found, it's pushed to the navigation stack.

Warning

Relative routes don't work with pages that are defined in a subclassedShell class, which is typicallyAppShell.xaml. Instead, only pages registered with theRouting.RegisterRoute method can be pushed onto the navigation stack using relative routes. For more information, seeRegister detail page routes.

Contextual navigation

Relative routes enable contextual navigation. For example, consider the following route hierarchy:

monkeys  detailsbears  details

When the registered page for themonkeys route is displayed, navigating to thedetails route will display the registered page for themonkeys/details route. Similarly, when the registered page for thebears route is displayed, navigating to thedetails route will display the registered page for thebears/details route. For information on how to register the routes in this example, seeRegister page routes.

Backwards navigation

Backwards navigation can be performed by specifying ".." as the argument to theGoToAsync method:

await Shell.Current.GoToAsync("..");

Backwards navigation with ".." can also be combined with a route:

await Shell.Current.GoToAsync("../route");

In this example, backwards navigation is performed, and then navigation to the specified route.

Important

Navigating backwards and into a specified route is only possible if the backwards navigation places you at the current location in the route hierarchy to navigate to the specified route.

Similarly, it's possible to navigate backwards multiple times, and then navigate to a specified route:

await Shell.Current.GoToAsync("../../route");

In this example, backwards navigation is performed twice, and then navigation to the specified route.

In addition, data can be passed through query properties when navigating backwards:

await Shell.Current.GoToAsync($"..?parameterToPassBack={parameterValueToPassBack}");

In this example, backwards navigation is performed, and the query parameter value is passed to the query parameter on the previous page.

Note

Query parameters can be appended to any backwards navigation request.

For more information about passing data when navigating, seePass data.

Invalid routes

The following route formats are invalid:

FormatExplanation
//page or ///pageGlobal routes currently can't be the only page on the navigation stack. Therefore, absolute routing to global routes is unsupported.

Use of these route formats results in anException being thrown.

Warning

Attempting to navigate to a non-existent route results in anArgumentException exception being thrown.

Debugging navigation

Some of the Shell classes are decorated with theDebuggerDisplayAttribute, which specifies how a class or field is displayed by the debugger. This can help to debug navigation requests by displaying data related to the navigation request. For example, the following screenshot shows theCurrentItem andCurrentState properties of theShell.Current object:

Screenshot of debugger.

In this example, theCurrentItem property, of typeFlyoutItem, displays the title and route of theFlyoutItem object. Similarly, theCurrentState property, of typeShellNavigationState, displays the URI of the displayed route within the Shell app.

Navigation stack

TheTab class defines aStack property, of typeIReadOnlyList<Page>, which represents the current navigation stack within theTab. The class also provides the following overridable navigation methods:

  • GetNavigationStack, returnsIReadOnlyList<Page>, the current navigation stack.
  • OnInsertPageBefore, that's called whenINavigation.InsertPageBefore is called.
  • OnPopAsync, returnsTask<Page>, and is called whenINavigation.PopAsync is called.
  • OnPopToRootAsync, returnsTask, and is called whenINavigation.OnPopToRootAsync is called.
  • OnPushAsync, returnsTask, and is called whenINavigation.PushAsync is called.
  • OnRemovePage, that's called whenINavigation.RemovePage is called.

The following example shows how to override theOnRemovePage method:

public class MyTab : Tab{    protected override void OnRemovePage(Page page)    {        base.OnRemovePage(page);        // Custom logic    }}

In this example,MyTab objects should be consumed in your Shell visual hierarchy instead ofTab objects.

Navigation events

TheShell class defines theNavigating event, which is fired when navigation is about to be performed, either due to programmatic navigation or user interaction. TheShellNavigatingEventArgs object that accompanies theNavigating event provides the following properties:

PropertyTypeDescription
CurrentShellNavigationStateThe URI of the current page.
SourceShellNavigationSourceThe type of navigation that occurred.
TargetShellNavigationStateThe URI representing where the navigation is destined.
CanCancelboolA value indicating if it's possible to cancel the navigation.
CancelledboolA value indicating if the navigation was canceled.

In addition, theShellNavigatingEventArgs class provides aCancel method that can be used to cancel navigation, and aGetDeferral method that returns aShellNavigatingDeferral token that can be used to complete navigation. For more information about navigation deferral, seeNavigation deferral.

TheShell class also defines theNavigated event, which is fired when navigation has completed. TheShellNavigatedEventArgs object that accompanies theNavigated event provides the following properties:

PropertyTypeDescription
CurrentShellNavigationStateThe URI of the current page.
PreviousShellNavigationStateThe URI of the previous page.
SourceShellNavigationSourceThe type of navigation that occurred.

Important

TheOnNavigating method is called when theNavigating event fires. Similarly, theOnNavigated method is called when theNavigated event fires. Both methods can be overridden in yourShell subclass to intercept navigation requests.

TheShellNavigatedEventArgs andShellNavigatingEventArgs classes both haveSource properties, of typeShellNavigationSource. This enumeration provides the following values:

  • Unknown
  • Push
  • Pop
  • PopToRoot
  • Insert
  • Remove
  • ShellItemChanged
  • ShellSectionChanged
  • ShellContentChanged

Therefore, navigation can be intercepted in anOnNavigating override and actions can be performed based on the navigation source. For example, the following code shows how to cancel backwards navigation if the data on the page is unsaved:

protected override void OnNavigating(ShellNavigatingEventArgs args){    base.OnNavigating(args);    // Cancel any back navigation.    if (args.Source == ShellNavigationSource.Pop)    {        args.Cancel();    }}

Navigation deferral

Shell navigation can be intercepted and completed or canceled based on user choice. This can be achieved by overriding theOnNavigating method in yourShell subclass, and by calling theGetDeferral method on theShellNavigatingEventArgs object. This method returns aShellNavigatingDeferral token that has aComplete method, which can be used to complete the navigation request:

public MyShell : Shell{    // ...    protected override async void OnNavigating(ShellNavigatingEventArgs args)    {        base.OnNavigating(args);        ShellNavigatingDeferral token = args.GetDeferral();        var result = await DisplayActionSheet("Navigate?", "Cancel", "Yes", "No");        if (result != "Yes")        {            args.Cancel();        }        token.Complete();    }    }
public MyShell : Shell{    // ...    protected override async void OnNavigating(ShellNavigatingEventArgs args)    {        base.OnNavigating(args);        ShellNavigatingDeferral token = args.GetDeferral();        var result = await DisplayActionSheetAsync("Navigate?", "Cancel", "Yes", "No");        if (result != "Yes")        {            args.Cancel();        }        token.Complete();    }    }

In this example, an action sheet is displayed that invites the user to complete the navigation request, or cancel it. Navigation is canceled by invoking theCancel method on theShellNavigatingEventArgs object. Navigation is completed by invoking theComplete method on theShellNavigatingDeferral token that was retrieved by theGetDeferral method on theShellNavigatingEventArgs object.

Warning

TheGoToAsync method will throw aInvalidOperationException if a user tries to navigate while there is a pending navigation deferral.

Pass data

Primitive data can be passed as string-based query parameters when performing URI-based programmatic navigation. This is achieved by appending? after a route, followed by a query parameter id,=, and a value:

async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e){    string elephantName = (e.CurrentSelection.FirstOrDefault() as Animal).Name;    await Shell.Current.GoToAsync($"elephantdetails?name={elephantName}");}

This example retrieves the currently selected elephant in theCollectionView, and navigates to theelephantdetails route, passingelephantName as a query parameter.

Pass multiple use object-based navigation data

Multiple use object-based navigation data can be passed with aGoToAsync overload that specifies anIDictionary<string, object> argument:

async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e){    Animal animal = e.CurrentSelection.FirstOrDefault() as Animal;    var navigationParameter = new Dictionary<string, object>    {        { "Bear", animal }    };    await Shell.Current.GoToAsync($"beardetails", navigationParameter);}

This example retrieves the currently selected bear in theCollectionView, as anAnimal. TheAnimal object is added to aDictionary with the keyBear. Then, navigation to thebeardetails route is performed, with theDictionary being passed as a navigation parameter.

Any data that's passed as anIDictionary<string, object> argument is retained in memory for the lifetime of the page, and isn't released until the page is removed from the navigation stack. This can be problematic, as shown in the following scenario:

  1. Page1 navigates toPage2 using theGoToAsync method, passing in an object calledMyData.Page2 then receivesMyData as a query parameter.
  2. Page2 navigates toPage3 using theGoToAsync method, without passing any data.
  3. Page3 navigates backwards with theGoToAsync method.Page2 then receivesMyData again as a query parameter.

While this is desirable in many scenarios, if it isn't desired you should clear theIDictionary<string, object> argument with theClear method after it's first been received by a page.

Pass single use object-based navigation data

Single use object-based navigation data can be passed with aGoToAsync overload that specifies aShellNavigationQueryParameters argument. AShellNavigationQueryParameters object is intended for single use navigation data that's cleared after navigation has occurred. The following example shows navigating while passing single use data:

async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e){    Animal animal = e.CurrentSelection.FirstOrDefault() as Animal;    var navigationParameter = new ShellNavigationQueryParameters    {        { "Bear", animal }    };    await Shell.Current.GoToAsync($"beardetails", navigationParameter);}

This example retrieves the currently selected bear in theCollectionView, as anAnimal that's added to theShellNavigationQueryParameters object. Then, navigation to thebeardetails route is performed, with theShellNavigationQueryParameters object being passed as a navigation parameter. After navigation has occurred the data in theShellNavigationQueryParameters object is cleared.

Receive navigation data

There are two approaches to receiving navigation data:

  1. The class that represents the page being navigated to, or the class for the page'sBindingContext, can be decorated with aQueryPropertyAttribute for each query parameter. For more information, seeProcess navigation data using query property attributes.
  2. The class that represents the page being navigated to, or the class for the page'sBindingContext, can implement theIQueryAttributable interface. For more information, seeProcess navigation data using a single method.

Process navigation data using query property attributes

Navigation data can be received by decorating the receiving class with aQueryPropertyAttribute for each string-based query parameter, object-based navigation parameter, orShellNavigationQueryParameters object:

[QueryProperty(nameof(Bear), "Bear")]public partial class BearDetailPage : ContentPage{    Animal bear;    public Animal Bear    {        get => bear;        set        {            bear = value;            OnPropertyChanged();        }    }    public BearDetailPage()    {        InitializeComponent();        BindingContext = this;    }}

In this example the first argument for theQueryPropertyAttribute specifies the name of the property that will receive the data, with the second argument specifying the parameter id. Therefore, theQueryPropertyAttribute in the above example specifies that theBear property will receive the data passed in theBear navigation parameter in theGoToAsync method call.

Important

String-based query parameter values that are received via theQueryPropertyAttribute are automatically URL decoded.

Warning

Receiving navigation data using theQueryPropertyAttribute isn't trim safe and shouldn't be used with full trimming or NativeAOT. Instead, you should implement theIQueryAttributable interface on types that need to accept query parameters. For more information, seeProcess navigation data using a single method,Trim a .NET MAUI app, andNative AOT deployment.

Process navigation data using a single method

Navigation data can be received by implementing theIQueryAttributable interface on the receiving class. TheIQueryAttributable interface specifies that the implementing class must implement theApplyQueryAttributes method. This method has aquery argument, of typeIDictionary<string, object>, that contains any data passed during navigation. Each key in the dictionary is a query parameter id, with its value corresponding to the object that represents the data. The advantage of using this approach is that navigation data can be processed using a single method, which can be useful when you have multiple items of navigation data that require processing as a whole.

The following example shows a view model class that implements theIQueryAttributable interface:

public class MonkeyDetailViewModel : IQueryAttributable, INotifyPropertyChanged{    public Animal Monkey { get; private set; }    public void ApplyQueryAttributes(IDictionary<string, object> query)    {        Monkey = query["Monkey"] as Animal;        OnPropertyChanged("Monkey");    }    ...}

In this example, theApplyQueryAttributes method retrieves the object that corresponds to theMonkey key in thequery dictionary, which was passed as an argument to theGoToAsync method call.

Important

String-based query parameter values that are received via theIQueryAttributable interface aren't automatically URL decoded.

Pass and process multiple items of data

Multiple string-based query parameters can be passed by connecting them with&. For example, the following code passes two data items:

async void OnCollectionViewSelectionChanged(object sender, SelectionChangedEventArgs e){    string elephantName = (e.CurrentSelection.FirstOrDefault() as Animal).Name;    string elephantLocation = (e.CurrentSelection.FirstOrDefault() as Animal).Location;    await Shell.Current.GoToAsync($"elephantdetails?name={elephantName}&location={elephantLocation}");}

This code example retrieves the currently selected elephant in theCollectionView, and navigates to theelephantdetails route, passingelephantName andelephantLocation as query parameters.

To receive multiple items of data, the class that represents the page being navigated to, or the class for the page'sBindingContext, can be decorated with aQueryPropertyAttribute for each string-based query parameter:

[QueryProperty(nameof(Name), "name")][QueryProperty(nameof(Location), "location")]public partial class ElephantDetailPage : ContentPage{    public string Name    {        set        {            // Custom logic        }    }    public string Location    {        set        {            // Custom logic        }    }    ...    }

In this example, the class is decorated with aQueryPropertyAttribute for each query parameter. The firstQueryPropertyAttribute specifies that theName property will receive the data passed in thename query parameter, while the secondQueryPropertyAttribute specifies that theLocation property will receive the data passed in thelocation query parameter. In both cases, the query parameter values are specified in the URI in theGoToAsync method call.

Warning

Receiving navigation data using theQueryPropertyAttribute isn't trim safe and shouldn't be used with full trimming or NativeAOT. Instead, you should implement theIQueryAttributable interface on types that need to accept query parameters. For more information, seeTrim a .NET MAUI app andNative AOT deployment.

Alternatively, navigation data can be processed by a single method by implementing theIQueryAttributable interface on the class that represents the page being navigated to, or the class for the page'sBindingContext:

public class ElephantDetailViewModel : IQueryAttributable, INotifyPropertyChanged{    public Animal Elephant { get; private set; }    public void ApplyQueryAttributes(IDictionary<string, object> query)    {        string name = HttpUtility.UrlDecode(query["name"].ToString());        string location = HttpUtility.UrlDecode(query["location"].ToString());        ...            }    ...}

In this example, theApplyQueryAttributes method retrieves the value of thename andlocation query parameters from the URI in theGoToAsync method call.

Note

String-based query parameters and object-based navigation parameters can be simultaneously passed when performing route-based navigation.

Back button behavior

Back button appearance and behavior can be redefined by setting theBackButtonBehavior attached property to aBackButtonBehavior object. TheBackButtonBehavior class defines the following properties:

  • Command, of typeICommand, which is executed when the back button is pressed.
  • CommandParameter, of typeobject, which is the parameter that's passed to theCommand.
  • IconOverride, of typeImageSource, the icon used for the back button.
  • IsEnabled, of typeboolean, indicates whether the back button is enabled. The default value istrue.
  • IsVisible, of typeboolean, indicates whether the back button is visible. The default value istrue.
  • TextOverride, of typestring, the text used for the back button.

All of these properties are backed byBindableProperty objects, which means that the properties can be targets of data bindings. EachBindableProperty has aOneTime binding mode, which means that data goes from the source to the target but only when theBindingContext changes.

All of these properties are backed byBindableProperty objects, which means that the properties can be targets of data bindings. TheCommand,CommandParameter,IconOveride, andTextOverideBindableProperty objects haveOneTime binding modes, which means that data goes from the source to the target but only when theBindingContext changes. TheIsEnabled andIsVisibleBindableProperty objects haveOneWay binding modes, which means that data goes from the source to the target.

The following code shows an example of redefining back button appearance and behavior:

<ContentPage ...>        <Shell.BackButtonBehavior>        <BackButtonBehavior Command="{Binding BackCommand}"                            IconOverride="back.png" />       </Shell.BackButtonBehavior>    ...</ContentPage>

TheCommand property is set to anICommand to be executed when the back button is pressed, and theIconOverride property is set to the icon that's used for the back button:

Screenshot of a Shell back button icon override.

Collaborate with us on GitHub
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, seeour contributor guide.

Feedback

Was this page helpful?

YesNo

In this article

Was this page helpful?

YesNo