Reusable Components and Styles in MAUI MVVM .NET 9 [GamesCatalog] - Part 3

Previous part: Creating a ListView MAUI MVVM .NET 9 [GamesCatalog] - Part 2

Step 1. First, let's style the page and the border of our fixed search field.

Step 2. In the styles and colors file, let's remove the existing stylizations.

Existing stylizations

Step 2.1. Styles.

<?xml version="1.0" encoding="UTF-8"?>
<?xaml-comp compile="true"?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
</ResourceDictionary>

Step 2.2. Colors.

<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <!--  Note: For Android please see also Platforms\Android\Resources\values\colors.xml  -->

</ResourceDictionary>

Step 3. Let's add to Colors.xaml the color that will be the background of the pages.

<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <!--  Note: For Android please see also Platforms\Android\Resources\values\colors.xml  -->

    <Color x:Key="MainBackgroundColor">#1B2D3E</Color>
    
</ResourceDictionary>

Step 4. In Styles.xaml, let's add the style for ContentPage, which references the MainBackgroundColor variable we created in Colors.xaml.

<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <Style ApplyToDerivedTypes="True" TargetType="ContentPage">
        <Setter Property="Padding" Value="0" />
        <Setter Property="BackgroundColor" Value="{StaticResource MainBackgroundColor}" />
    </Style>
  
</ResourceDictionary>

Step 5. After the ContentPage style, let's add some basic parameters for our search field border. We will define a key to control its usage.

    <Style x:Key="BorderPrimary" TargetType="Border">
        <Setter Property="BackgroundColor" Value="Transparent" />
        <Setter Property="Padding" Value="10" />
    </Style>

Step 6. We reference the style in the style property of the border of our search field.

  <Border
      Padding="10,0,10,5"
      HorizontalOptions="FillAndExpand"
      Style="{StaticResource BorderPrimary}">

Step 7. We now have the page with the background and the border style for the search field that we defined.

Border Style

Step 8. Let's create the file for the component that will handle text input in the system.

Component

Step 9. We create it as a VerticalStackLayout, with the parameters LabelText, Enabled, MaxLength, and Text to handle text input.

<?xml version="1.0" encoding="utf-8"?>
<VerticalStackLayout
    x:Class="GamesCatalog.Components.BorderedEntry"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Name="this"
    Margin="0,5,0,0">

    <Label 
        Style="{StaticResource LblHEntry}" 
        Text="{Binding Source={x:Reference this}, Path=LabelText}" />

    <Border 
        IsEnabled="{Binding Source={x:Reference this}, Path=Enabled}" 
        Style="{StaticResource EntryBorders}">

        <Entry
            IsEnabled="{Binding Source={x:Reference this}, Path=Enabled}"
            MaxLength="{Binding Source={x:Reference this}, Path=MaxLength}"
            Style="{StaticResource Entry}"
            Text="{Binding Source={x:Reference this}, Path=Text}" />
            
    </Border>

</VerticalStackLayout>

Step 10. Let's style the fields.

Step 10.1. Defining basic colors in Colors.xaml.

<Color x:Key="White">White</Color>
<Color x:Key="Black">Black</Color>
<Color x:Key="ActiveColor">#92CBFF</Color>
<Color x:Key="lightGray">#E1E1E1</Color>
<Color x:Key="Gray">#ACACAC</Color>

Step 10.2. Creating the styles for the component in Styles.xaml.

<Style x:Key="LblHEntry" TargetType="Label">
    <Setter Property="TextColor" Value="{StaticResource lightGray}" />
    <Setter Property="BackgroundColor" Value="Transparent" />
    <Setter Property="FontFamily" Value="OpenSansSemibold" />
    <Setter Property="FontSize" Value="14" />
    <Setter Property="Padding" Value="5,0,0,0" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal" />
                <VisualState x:Name="Disabled">
                    <VisualState.Setters>
                        <Setter Property="TextColor" Value="{StaticResource Gray}" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

<Style x:Key="EntryBorders" TargetType="Border">
    <Setter Property="Padding" Value="-5,0,0,0" />
    <Setter Property="HorizontalOptions" Value="FillAndExpand" />
    <Setter Property="BackgroundColor" Value="#101923" />
    <Setter Property="Stroke" Value="{StaticResource ActiveColor}" />
    <Setter Property="StrokeShape" Value="RoundRectangle 5" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal" />
                <VisualState x:Name="Disabled">
                    <VisualState.Setters>
                        <Setter Property="Stroke" Value="#2B659B" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

<Style x:Key="Entry" TargetType="Entry">
    <Setter Property="TextColor" Value="{StaticResource White}" />
    <Setter Property="BackgroundColor" Value="Transparent" />
    <Setter Property="FontAttributes" Value="Bold" />
    <Setter Property="FontSize" Value="18" />
    <Setter Property="PlaceholderColor" Value="{StaticResource Gray}" />
    <Setter Property="MinimumHeightRequest" Value="50" />
    <Setter Property="Margin" Value="5,0,0,0" />
</Style>

Step 11. We declare the properties in the class.

public partial class BorderedEntry : VerticalStackLayout
{
    public BorderedEntry()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty TextProperty = BindableProperty.Create(
        propertyName: nameof(Text),
        returnType: typeof(string),
        declaringType: typeof(BorderedEntry),
        defaultValue: null,
        defaultBindingMode: BindingMode.TwoWay);

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public static readonly BindableProperty LabelTextProperty = BindableProperty.Create(
        propertyName: nameof(LabelText),
        returnType: typeof(string),
        declaringType: typeof(BorderedEntry),
        defaultValue: null,
        defaultBindingMode: BindingMode.OneWay);

    public string LabelText
    {
        get => (string)GetValue(LabelTextProperty);
        set => SetValue(LabelTextProperty, value);
    }

    public static readonly BindableProperty EnabledProperty = BindableProperty.Create(
        propertyName: nameof(Enabled),
        returnType: typeof(bool),
        declaringType: typeof(BorderedEntry),
        defaultValue: true,
        defaultBindingMode: BindingMode.OneWay);

    public bool Enabled
    {
        get => (bool)GetValue(EnabledProperty);
        set => SetValue(EnabledProperty, value);
    }

    public static readonly BindableProperty MaxLengthProperty = BindableProperty.Create(
        propertyName: nameof(MaxLength),
        returnType: typeof(int),
        declaringType: typeof(BorderedEntry),
        defaultValue: 100,
        defaultBindingMode: BindingMode.TwoWay);

    public int MaxLength
    {
        get => (int)GetValue(MaxLengthProperty);
        set => SetValue(MaxLengthProperty, value);
    }
}

Step 12. In IGDBResults.xaml, let's define the component's address in the ContentPage and reference it as our search field.

ContentPage

Step 13. Codes.

Step 13.1. In ContentPage.

 xmlns:components="clr-namespace:GamesCatalog.Components"

Step 13.2. The Component call.

<components:BorderedEntry 
    LabelText="Search" 
    MaxLength="100" 
    Text="{Binding SearchText}" />

Step 14. In IGDBResultsVM, let's add the binding to SearchText.

private string searchText;

public string SearchText
{
    get => searchText;
    set
    {
        if (searchText != value)
        {
            SetProperty(ref searchText, value);
        }
    }
}

Step 15. With this, we have our stylized search field.

IGDB Result

Up Next
    Ebook Download
    View all
    Learn
    View all