MAUI Environment Ribbon - Shell integration (Part 2)


Chapters in this series:

  1. Intro and basic UI
  2. Shell integration
  3. NavigationPage integration
  4. UI customization
  5. Optimization and wrap up
  6. Download the code

Creating the UI was quite easy. But now for the hard part - we don't want to place this control into each page manually and we don't want to create a dependency on some page base class or another solution that would force us to change the UI code that is already written.

We have these requirements for using the control:

  • Don't be forced to modify our existing pages just to use it.
  • Be able to use it with Shell as well as with NavigationPage.
  • Make it easy to add it to the application.
  • Don't effect the app performance (at least in production environment).

What we want to achieve is to be able to just call method AddEnvironmentRibbon() and get the control automatically inserted into all pages.

We also need to consider different scenarios, the app can use Shell or NavigationPage for navigation so we need to support both.

The control is intended to only be used in development and testing environments - we don't want to display such a ribbon in a production app. So if it impacts the performance a little bit it isn't necessarily a blocker. However we don't want it to change the behavior of the screens and we don't want to be forced to modify existing pages and controls to incorporate it.

Shell integration

Let's start with Shell navigation as it's easier to handle. We'll use the Navigated event that's fired from Shell to achieve this.

Here's the basic code for the AddEnvironmentRibbon extension method for Shell:

public static class ShellExtensions
    public static Shell AddEnvironmentRibbon(this Shell shell)
        shell.Navigated += Shell_Navigated;
        return shell;

    private static void Shell_Navigated(object? sender, ShellNavigatedEventArgs e)
        if (sender is Shell shell
            && shell.CurrentPage is ContentPage contentPage)
            var newRootGrid = new Grid();

            newRootGrid.Children.Add(new EnvironmentRibbon());
            contentPage.Content = newRootGrid;

This fires everytime that Shell navigates to a page. What we do is that we add a new top layer Grid to the current page and add wrap the previous content in the new wrapper while also adding a new EnvironmentRibbon control to the top level. This way we achieve that the control is displayed over any previous content and it gets added to all the pages as we navigate through our app.

When we want to use it now we just call the extension method on our app's shell and we're good to go.

public partial class App
    public App()

        var appShell = new AppShell()

        MainPage = appShell;

The ribbon will appear below the top navigation bar if the app uses the default navigation bar. It's not that easy to draw into the navigation bar especially if the toolbar items are used so I opted to choose this way. Moreover from experience in real-world applications we usually opt to turn off the default navigation bar and create a custom one so I don't think this is a big issue. However, if this would be requested by more people I might look into embedding the control within the navigation bar.

It's quite simple to integrate it with Shell and it works with tabs, flyouts, navigation to other pages etc.

Here are some more screenshots with different pages (and more adorable cats):

Previous chapter Next chapter

Roman Jašek
Roman Jašek


Roman je Microsoft MVP a pracuje ako software architekt v RIGANTI. Jeho hlavná oblasť je mobilný vývoj v MAUI. Okrem toho sa venuje aj ďalším častiam vývoja v .NET ekosystéme - webovému vývoju v ASP.NET, cloudovému v Azure atď. Vo voľnom čase sa venuje organizácii prednášok a konferencií v rámci WUG CZ a učí aplikačný vývoj s použitím .NET MAUI a Blazoru na univerzitách v Brne.

Ostatní články z kategorie: RIGANTI Blog