My two cents on Xamarin Forms Shell

As a Xamarin developer with a few years of experience, I decided to take a look at the new way to create mobile apps using Xamarin Forms Shell.

What is the big fuzz about Xamarin Forms Shell? What are they trying to achieve? Let’s find out!

I created a new project with the newest template ( Shell Forms App ) the template added plenty of files and some dependencies to my project for example:

  • Folders to follow an MVVM pattern: Models, Views, ViewModels, Services
  • Xamarin.Essentials NuGet package is installed by default
  • AppShell.xaml
  • An AboutPage.xaml and a ItemDetailPage.xaml
  • A class called MockDataStore.cs to help you implement your API

First thought

Things are getting easier?

The second thought came out with this line inside AboutPage.cs
[DesignTimeVisible(false)] What is this you ask me? Well…
From Microsoft docs:

DesignTimeVisibleAttribute marks a component’s visibility. If Yes is present, a visual designer can show this component on a designer.

So with this attribute, you can specify code that will only execute when the application is or isn’t running in the previewer.

I am not sure if this attribute was implemented before, my first guess is that it wasn’t… Since the Xamarin.Forms previewer was very buggy. #NoRegret

Keep diving in the code and you will see:
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"

What is this??

Design time data is fake data you set to make your controls easier to visualize in the XAML Previewer. After adding the namespaces, you can put d: in front of any attribute or control to show it in the XAML Previewer. Elements with d: aren’t shown at runtime.

For example, you can add text to a label that usually has data bound to it.

<Label Text="{Binding Name}" d:Text="Name!" />

So yeah! The template is actually helping you to use the XAML previewer (Which indeed is working better than before I can tell). Xamarin Forms team and Visual Studio team are doing just great! So my guess is that they are pushing hard on this to get rid of tools like Gorilla player and LiveXaml.

Second thought

For default, the template will have a couple of tabs and a tabbed page inside the AppShell.xaml file to display a list and an info page. I tried a simple thing… instead of showing a TabbedPage I wanted to use a Flyout and inside the flyout items add a TabbedPage with more Tabs.

I think that the concept I am looking for is: Tabbed Page inside FlyoutItem right? It should be simple…

Let’s go step by step by step, first we are going to show the Flyout menu:

<Shell.FlyoutHeaderTemplate>
  <DataTemplate>
        <Grid BackgroundColor="Black" HeightRequest="200">
            <Label Text="Shell Hands-on"
                   TextColor="White"
                   FontAttributes="Bold"
                   HorizontalTextAlignment="Center"
                   VerticalTextAlignment="Center" />
        </Grid>
    </DataTemplate>
</Shell.FlyoutHeaderTemplate>
<FlyoutItem Title="Browse">
    <Tab>
        <ShellContent>
            <local:ItemsPage />
        </ShellContent>
    </Tab>
</FlyoutItem>
<FlyoutItem Title="About">
    <Tab>
        <ShellContent>
            <local:AboutPage />
        </ShellContent>
    </Tab>
</FlyoutItem>

After that, we can add multiple pages using ShellContent inside the Tab tag ( *For some reason)

* “There is a TabbedPage tag that may generate some confusion but I suppose that is still referring to the previous way of coding Xamarin.Forms”

<FlyoutItem Title="Browse">
    <Tab>
        <ShellContent Title="First">
            <ContentPage Title="First Page">
                <Grid
                    HorizontalOptions="CenterAndExpand"
                    VerticalOptions="CenterAndExpand">
                    <Label Text="First page" />
                </Grid>
            </ContentPage>
        </ShellContent>
        <ShellContent Title="Second">
            <ContentPage Title="Second Page">
                <Grid
                    HorizontalOptions="CenterAndExpand"
                    VerticalOptions="CenterAndExpand">
                    <Label Text="Second page" />
                </Grid>
            </ContentPage>
        </ShellContent>
        <ShellContent Title="Items">
            <local:ItemsPage />
        </ShellContent>
    </Tab>
</FlyoutItem>
<FlyoutItem Title="About">
    <Tab>
        <ShellContent>
            <local:AboutPage />
        </ShellContent>
    </Tab>
</FlyoutItem>

If you are using Tab the TabbedPage will be rendered on top on both platforms, but on iOS, the swipe feature is not implemented, which is a great add-in on Android, nevertheless, the swipe gesture on the Tabs at the same time with a Flyout will generate conflicts, so keep an eye on that.

Also there is an open issue which is not rendering correctly the ListViews if you have multiple tabs on iOS, for reference you can follow up here: https://github.com/xamarin/Xamarin.Forms/issues/6253

Based on Microsoft docs and a very important thing to consider is that you can’t have Flyout and TabBar at the same time. You can read more at:
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/tabs

So? That makes me wonder, can you actually combine a Flyout, bottom tabbed pages, and top tabbed pages? Maybe that could be another blog post!

Another thing to emphasize here is the importance of ContentTemplate usage inside ShellContent objects/tags since “Every ContentPage object in a ShellContent object is created during application startup, which can lead to a poor startup experience” so this is a must!

Last but not least

Navigation! And this topic is really the exiting part and as David Ortinau mentioned:

“Shell’s new URI based navigation service adds route-based navigation to the existing INavigationservice. It’s not a replacement, although you may eventually love it and never use PushAsync again. “

The first thing you have to do to implement the new navigation is to add a Route tag to every Element like FlyoutItem / Tab / ShellContent you want to navigate for example:

You can also register routes from code behind like this:
Routing.RegisterRoute("detail", typeof(ItemsPage));

<ShellContent Route="detail" Title="Items">
    <local:ItemsPage />
</ShellContent> 

In order to navigate you will have to use something like this:
await Shell.Current.GoToAsync("//detail");
And you can access it from anywhere so bye…bye…bye INavigation object inside the ViewModels. Wooooot!

But wait! What if my class needs a parameter?

Don’t worry they have you covered, there are a couple of things that you need to add in order to pass parameters using URI-based navigation for example:

You will have to add the:
[QueryProperty("Item", "item")] Tag and a property to the Class or the ViewModel that is expecting this parameter:

public string Item
 {
     set
     {
         viewModel = Uri.UnescapeDataString(value);
     }
 }

And send it on your URI:
await Shell.Current.GoToAsync($"itemDetail/item={vm}");

Unfortunately, I was not able to find much information on how to send parameters that are not strings (Which then can be parsed to different types), so I am not sure if you can actually send a whole object (This could be another post).

I remember a bug on Android that opened multiple pages if the user keeps tabbing on a cell inside a ListView, if you didn’t handle that correctly this could easily happen, with Shell this is fixed! #Yeah!

A lot of information huh? This are my first thoughts while diving in on Xamarin Forms Shell but I can tell that I will definitely create my next Xamarin.Forms project using Shell. What about yourself? Let me know your thoughts or questions on the comments section and don’t forget to subscribe to my feed.

This post is part of the #XamarinUIJuly series thanks to @devnl to have this awesome idea!

5 thoughts on “My two cents on Xamarin Forms Shell

  1. “I am not sure if you can actually send a whole object (This could be another post).”
    This is a ‘must’ post 😀 with passing parameters i think everyone had in mind if and how they can pass an object

    Liked by 1 person

Leave a comment