Learn everything you need to know about using Shell in your .NET MAUI applications. Today: Create a hierarchy and customize the Shell file to suit your needs.
Let’s continue our series on Mastering the .NET MAUI Shell. In the previous article in this series, you learned how to create your own Shell file and add content to it. Now it’s time to learn how to create a hierarchy and customize it to your needs. Let’s get started!
Add new utilities to the app
Let’s add some additional utilities to our application so that we can properly visualize the upcoming examples in this guide.
Third Utility: Awesome Image Editor
The third utility to add to your application is an image editor. How complicated would it be to create such a control? Sure, implementing this type of control from scratch could take days. Fortunately, Telerik UI suite for .NET MAUI has an image editor control that you can quickly and easily integrate into your application.
This utility consists of the following components:
To integrate this control into your application, create a new ContentPage. CoolEditor.xaml
Includes:
<Grid RowDefinitions="Auto,*">
<telerik:RadImageEditorToolbar ImageEditor="{x:Reference imageEditor}" />
<telerik:RadImageEditor x:Name="imageEditor" Grid.Row="1" />
</Grid>
Also, use the following C# code to load the image into the control behind the code.
public CoolEditor()
{
InitializeComponent();
this.imageEditor.Source = ImageSource.FromFile("dotnet_bot.png");
}
Pretty simple, right? The new utility basically implements several image manipulation functions, and looks like this:
Now let’s look at how to create a fourth utility.
Fourth Utility: Word Counter
The following utility is one that can be very useful to users, it is a word counter that allows the user to know the number of words written in a text box. This utility consists of the following controls:
- Main
Grid
Group controls and specify background colors and utility layouts. - no way
Border
Make the text box where the user enters the words to be calculated more visible. - not
Editor
Have the user enter text containing the words they want to count. - no way
Label
To display the number of words counted
Let’s add a new ContentPage. WordCounter.xaml
Please enter the following code.
<Grid BackgroundColor="DarkSlateBlue" RowDefinitions=".8*,.2*">
<Border Margin="10" StrokeShape="RoundRectangle 12">
<Editor
x:Name="WordsInput"
Background="MediumPurple"
Placeholder="Your words"
PlaceholderColor="LightGray"
TextChanged="WordsInput_TextChanged" />
</Border>
<Label
x:Name="WordCountLabel"
Grid.Row="1"
FontSize="24"
HorizontalOptions="Center"
Text="0 Words"
TextColor="White"
VerticalOptions="Center" />
</Grid>
Behind the code, the function to count words is defined as follows:
public partial class WordCounter : ContentPage
{
public WordCounter()
{
InitializeComponent();
}
private void WordsInput_TextChanged(object sender, TextChangedEventArgs e)
{
var newText = e.NewTextValue;
int wordCount = CountWords(newText);
WordCountLabel.Text = $"{wordCount} Words";
}
private int CountWords(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return 0;
}
var words = text.Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
return words.Length;
}
}
Once the new utility is implemented, it will look like this:
With this, we now have enough utility to improve the layers of our application. We will see how to do this in the next section.
Add subtab to hierarchy
So far we have created four utilities that are part of our application, and as you can remember, they are in the same hierarchy within the Flyout, as you can see in the following image.
What we’re currently working on is that the .NET MAUI framework will automatically generate: FlyoutItem
Each type element ShellContent
. You may think that this hierarchy is fine now, but as your application grows with new utilities, the sidebar will become crowded with elements and difficult to navigate. This is where you can start adding tabs and redefining the initial hierarchy to better organize your app pages.
Let’s say we want a new layer that categorizes utilities, like in the image below.
To group tools by category, you must explicitly define: FlyoutItem
Enter the element in MyShell.xaml
File, nested ShellContent
We made it. In our example, I will make two. FlyoutItem
Using elements representing categories, we get the following format:
<Shell
x:Class="MAUIUtils.MyShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:UtilPages="clr-namespace:MAUIUtils.Pages"
Title="MyShell"
BackgroundColor="#F9AA33">
<FlyoutItem Title="Creative Tools" Icon="dotnet_bot.png">
<ShellContent
Title="Image Editor"
ContentTemplate="{DataTemplate UtilPages:CoolEditor}"
Icon="dotnet_bot.png" />
<ShellContent
Title="URL to QR"
ContentTemplate="{DataTemplate UtilPages:URLToQR}"
Icon="dotnet_bot.png" />
</FlyoutItem>
<FlyoutItem Title="Productivity Tools" Icon="dotnet_bot.png">
<ShellContent
Title="Word Counter"
ContentTemplate="{DataTemplate UtilPages:WordCounter}"
Icon="dotnet_bot.png" />
<ShellContent
Title="Color Generator"
ContentTemplate="{DataTemplate UtilPages:RandomColor}"
Icon="dotnet_bot.png" />
</FlyoutItem>
</Shell>
This will only add two FlyoutItems to the Flyout. You can see this in the XAML code: Title
and Icon
The properties for each FlyoutItem provide the following results:
Meanwhile, each category has several tabs created representing its utilities.
Adding a new level of hierarchy using .NET MAUI Shell
.NET MAUI Shell can add a higher level of hierarchy than we have seen before. Let’s say your application continues to grow and you now need to create subcategories in your application, as in the following example.
This new category adds the following subcategories: Text toolHere we will group all the text related tools. To achieve this in our XAML code we need to explicitly create an element of type. Tab
The tools in this subcategory are nested as follows:
<FlyoutItem Title="Productivity Tools" Icon="dotnet_bot.png">
<Tab Title="Text Tools" Icon="dotnet_bot.png">
<ShellContent
Title="Word Counter"
ContentTemplate="{DataTemplate UtilPages:WordCounter}"
Icon="dotnet_bot.png" />
<ShellContent
Title="Color Generator"
ContentTemplate="{DataTemplate UtilPages:RandomColor}"
Icon="dotnet_bot.png" />
</Tab>
<Tab Title="Other Tools" Icon="dotnet_bot.png">
<ShellContent
Title="Word Counter"
ContentTemplate="{DataTemplate UtilPages:WordCounter}"
Icon="dotnet_bot.png" />
<ShellContent
Title="Color Generator"
ContentTemplate="{DataTemplate UtilPages:RandomColor}"
Icon="dotnet_bot.png" />
</Tab>
</FlyoutItem>
In the above code, we have grouped the two ShellContents in the Productivity Tools category into a new group. Tab
Then duplicate it to show the resulting visual appearance.
In the image above, you can see that a new tab section has been created on top of the page. This creates a new level in the hierarchy of the app.
Shell Customization
.NET MAUI allows you to modify several visual aspects of the shell, as you can see below.
Customize Flyout Icons
If for some reason you want to change the hamburger icon that is part of the Shell, you can do so by: FlyoutIcon
Properties of the Shell page as shown below:
<Shell
x:Class="MAUIUtils.MyShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:UtilPages="clr-namespace:MAUIUtils.Pages"
Title="MyShell"
BackgroundColor="#F9AA33"
FlyoutIcon="dotnet_bot.png">
The execution result is as follows.
Customizing the Flyout Header and Flyout Footer
.NET MAUI also allows you to customize: Shell.FlyoutHeader
and Shell.FlyoutFooter
Properties that modify the header and footer of a flyout, as in the following example:
<Shell.FlyoutHeader>
<Grid BackgroundColor="DarkSlateBlue" HeightRequest="150">
<Label
FontSize="24"
HorizontalOptions="Center"
Text="MAUI Utils"
TextColor="White"
VerticalOptions="Center" />
</Grid>
</Shell.FlyoutHeader>
<Shell.FlyoutFooter>
<VerticalStackLayout HeightRequest="100">
<Label
FontSize="12"
HorizontalOptions="Center"
Text="Powered By"
TextColor="Gray"
VerticalOptions="Center" />
<Label
FontSize="30"
HorizontalOptions="Center"
Text="Progress"
TextColor="#5CE500"
VerticalOptions="Center" />
</VerticalStackLayout>
</Shell.FlyoutFooter>
The result of the above code is as follows.
Customizing Flyout Items
Undoubtedly, a common question is how to customize Flyout items. This is possible by defining: Shell.ItemTemplate
Property we can redeem FlyoutIcon
and Title
Properties for adding and customizing controls, as in the following example:
<Shell.ItemTemplate>
<DataTemplate>
<Grid
ColumnDefinitions=".2*, .8*"
HeightRequest="75"
RowSpacing="0">
<Rectangle
x:Name="background"
Grid.ColumnSpan="2"
Fill="Black"
Opacity=".5" />
<Image
HeightRequest="30"
Source="{Binding FlyoutIcon}"
VerticalOptions="Center" />
<Label
Grid.Column="1"
Margin="20,0,0,0"
FontSize="20"
Text="{Binding Title}"
TextColor="White"
VerticalOptions="Center" />
</Grid>
</DataTemplate>
</Shell.ItemTemplate>
As a result, the following results occur:
Customize the appearance of selected elements
If modified Shell.ItemTemplate
Properties, you are probably now faced with the dilemma of how to modify the visual appearance of the element selected by the user. To solve this problem, you need to modify the following: VisualStateManager.VisualStateGroups
Properties specify various states and visual appearances of an element, as follows:
<Shell.ItemTemplate>
<DataTemplate>
<Grid
...
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter TargetName="background" Property="Rectangle.Fill" Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter TargetName="background" Property="Rectangle.Fill" Value="DarkRed" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Grid>
</DataTemplate>
</Shell.ItemTemplate>
In my case, I defined it within a container grid so that I could access the defined controls. Shell.ItemTemplate
The result is as follows:
Customizing the colors of the shell page
.NET MAUI Shell allows you to customize the colors of the Shell pages through a variety of properties. Below are the properties (starting with the term). shell.x) can be used to adjust the colors of the Shell page.
<Shell
x:Class="MAUIUtils.MyShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:UtilPages="clr-namespace:MAUIUtils.Pages"
Title="MyShell"
BackgroundColor="#F9AA33"
FlyoutIcon="dotnet_bot.png"
Shell.ForegroundColor="Yellow"
Shell.TitleColor="DarkMagenta"
Shell.UnselectedColor="DarkGreen">
You can also modify the visual appearance of a tab through a series of attached properties that start with a term. Shell.TabBar
It will be displayed as follows:
<Shell
x:Class="MAUIUtils.MyShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:UtilPages="clr-namespace:MAUIUtils.Pages"
Title="MyShell"
BackgroundColor="#F9AA33"
FlyoutIcon="dotnet_bot.png"
Shell.ForegroundColor="Yellow"
Shell.TabBarBackgroundColor="#1D1F24"
Shell.TabBarDisabledColor="#1D1F24"
Shell.TabBarForegroundColor="Yellow"
Shell.TabBarTitleColor="#9E86FF"
Shell.TabBarUnselectedColor="#555A62"
Shell.TitleColor="DarkMagenta"
Shell.UnselectedColor="DarkGreen">
Finally, it is important to emphasize the following fundamentally: Styles.xaml
The files generated from a .NET MAUI project have the following sections:
<Style ApplyToDerivedTypes="True" TargetType="Shell">
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource OffBlack}}" />
<Setter Property="Shell.ForegroundColor" Value="{OnPlatform WinUI={StaticResource Primary}, Default={StaticResource White}}" />
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.UnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray200}}" />
<Setter Property="Shell.NavBarHasShadow" Value="False" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource Magenta}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource Gray900}, Dark={StaticResource Gray200}}" />
</Style>
Here you can specify different values ​​for shell custom properties for both dark and light modes of your application.
The custom results are as follows:
Now that you know how to create a hierarchy using Shell and how to customize colors, in the next post you will learn how to perform navigation using Shell, including passing parameters, and how to create your own SearchHandler that allows users to perform searches.