Dynamic Styles and Appearance Behavior in MAUI [GamesCatalog] - Part 12

Previous part: Updating an Object in the Local Database in MAUI .NET 9 [GamesCatalog] - Part 11

Step 1. Create the main ContentPage and its ViewModel.

Content page

MainVM Code

namespace GamesCatalog.ViewModels
{
    public partial class MainPageVM : ViewModelBase
    {
    }
}

Main. xaml.cs Code

using GamesCatalog.ViewModels;
namespace GamesCatalog.Views
{
    public partial class Main : ContentPage
    {
        public Main(MainVM mainVM)
        {
            InitializeComponent();
            BindingContext = mainVM;
        }
    }
}

Step 2. Add the shell to the CreateMauiApp() in MauiProgram.

MauiProgram

Code

builder.Services.AddTransientWithShellRoute<Main, MainVM>(nameof(Main));

Step 3. Set Main as the main route. For now, let’s also disable the sidebar since we won’t need it yet.

Side bar

Code

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="GamesCatalog.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:GamesCatalog.Views"
    Shell.FlyoutBehavior="Disabled">
    <ShellContent
        ContentTemplate="{DataTemplate local:Main}"
        FlyoutItemIsVisible="False"
        Route="MainPage" />

</Shell>

Step 4. In Main. xaml, remove the NavBar and set its structure to Grid.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="GamesCatalog.Views.Main"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:Icons="clr-namespace:GamesCatalog.Resources.Fonts"
    Shell.NavBarIsVisible="False">

    <Grid VerticalOptions="Fill" x:Name="PageGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    </Grid>
</ContentPage>

Step 4.1. After that, inside the main grid (named PageGrid), we’ll define two parts: the inner body and a button to add games to our list.

<ScrollView>
    <Grid VerticalOptions="Fill" x:Name="BodyGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="40" />
        </Grid.RowDefinitions>
    </Grid>
</ScrollView>

<Button
    x:Name="BtnAddGame"
    Command="{Binding GoToIGDBResultsCommand}"
    Style="{StaticResource BtnAddGame}"
    Text="Add Game">
    <Button.ImageSource>
        <FontImageSource
            FontFamily="FontAwesomeIcons"
            Glyph="{x:Static Icons:IconFont.Plus}"
            Size="30" />
    </Button.ImageSource>
</Button>

Step 4.2. Let’s create a local style for this button.

Local style

Code

<ContentPage.Resources>
    <Style x:Key="BtnAddGame" TargetType="Button">
        <Setter Property="Margin" Value="0,0,30,30" />
        <Setter Property="BackgroundColor" Value="{StaticResource Success}" />
        <Setter Property="FontAttributes" Value="Bold" />
        <Setter Property="FontSize" Value="20" />
        <Setter Property="HorizontalOptions" Value="End" />
        <Setter Property="VerticalOptions" Value="End" />
    </Style>
</ContentPage.Resources>

Step 5. In the MainVM, create the command for this button:

[RelayCommand]
private Task GoToIGDBResults() => Shell.Current.GoToAsync($"{nameof(IGDBResults)}");

Step 6. Now, we have a fixed button at the bottom corner of the main screen.

Add game

Step 7. Let’s add an icon to show the status of the internet connection. Inside the grid we named BodyGrid, in the second row, we’ll insert a HorizontalStackLayout to display footer information. Inside it, add a label with a Wi-Fi icon that has its color defined by the ViewModel.

View model

Step 8. We'll check for internet connectivity every time the main page is focused. To do that, we’ll use the EventToCommandBehavior from the toolkit.

Internet connectivity

Code

Add the Toolkit to the page.

xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"

Add the EventToCommandBehavior to the page’s Behaviors.

<ContentPage.Behaviors>
    <toolkit:EventToCommandBehavior
        BindingContext="{Binding BindingContext, Source={x:Reference this}, x:DataType=MainVM}"
        Command="{Binding AppearingCommand}"
        EventName="Appearing" />
</ContentPage.Behaviors>

Step 9. In MainVM.cs, add two properties: one to control the connection icon color and another to control access to the "Add Game" button.

private bool btnAddGameIsEnabled = true;
public bool BtnAddGameIsEnabled
{
    get => btnAddGameIsEnabled;
    set
    {
        if (value != btnAddGameIsEnabled)
        {
            SetProperty(ref btnAddGameIsEnabled, value);
        }
    }
}
private Color isConnectedColor = Colors.Green;
public Color IsConnectedColor
{
    get => isConnectedColor;
    set
    {
        if (value != isConnectedColor)
        {
            SetProperty(ref isConnectedColor, value);
        }
    }
}

Step 10. Add the Appearing command, which triggers every time the page comes into focus.

[RelayCommand]
private async Task Appearing()
{
    if (Connectivity.NetworkAccess != NetworkAccess.Internet)
    {
        IsConnectedColor = Colors.Red;
        BtnAddGameIsEnabled = false;
    }
    else
    {
        IsConnectedColor = Colors.Green;
        BtnAddGameIsEnabled = true;
    }
}

Step 11. In Main. xaml, in the "Add Game" button (named BtnAddGame), add the variable that controls access to the game addition screen and a Trigger to change the button style when disabled.

<Button
    x:Name="BtnAddGame"
    Command="{Binding GoToIGDBResultsCommand}"
    IsEnabled="{Binding BtnAddGameIsEnabled}"
    Style="{StaticResource BtnAddGame}"
    Text="Add Game">

    <Button.ImageSource>
        <FontImageSource
            FontFamily="FontAwesomeIcons"
            Glyph="{x:Static Icons:IconFont.Plus}"
            Size="30" />
    </Button.ImageSource>

    <Button.Triggers>
        <Trigger TargetType="Button" Property="IsEnabled" Value="False">
            <Setter Property="TextColor" Value="{StaticResource Gray}" />
            <Setter Property="ImageSource">
                <Setter.Value>
                    <FontImageSource
                        FontFamily="FontAwesomeIcons"
                        Glyph="{x:Static Icons:IconFont.Plus}"
                        Size="30"
                        Color="{StaticResource Gray}" />
                </Setter.Value>
            </Setter>
        </Trigger>

        <Trigger TargetType="Button" Property="IsEnabled" Value="True">
            <Setter Property="TextColor" Value="{StaticResource White}" />
            <Setter Property="ImageSource">
                <Setter.Value>
                    <FontImageSource
                        FontFamily="FontAwesomeIcons"
                        Glyph="{x:Static Icons:IconFont.Plus}"
                        Size="30"
                        Color="{StaticResource White}" />
                </Setter.Value>
            </Setter>
        </Trigger>
    </Button.Triggers>
</Button>

Step 12. Now we have the icon in the corner of the screen to indicate no internet connection, and the "Add Game" button is disabled when there is no connection.

Icon

Red icon and disabled button when there’s no internet.

Internet

Green icon and accessible button when there is internet.

In the next step, we’ll continue building our main screen by adding components to display the number of games we’ve added by status.

Up Next
    Ebook Download
    View all
    Learn
    View all