Search code examples
c#.netxamlmaui

.Net MAUI Page Inheritance - How To Display Both Pages' Contents?


Throughout the development of my app, I found that many pages will have a very similar content to one another, with only one difference amongst them. In order to prevent duplicated code and, consequently, more maintenance, I decided to make all of them inherit from a single base page.

However, no matter what I did, the content would always be displayed incorrectly. Instead of showing the content of both the base page and the child page, only the child page would be displayed.

I made a test project to keep experimenting until I found a solution, but to no avail. Here's what I have so far:

Base Page .xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.MainPage"
             Title="MainPage">

  <VerticalStackLayout>
    
    <!-- The child page will need access to this label as well -->
    <Label x:Name="LabelMain" Text="MainPage content."/>
    
    <!-- This is where the child page's content should be -->
    <ContentPresenter/>
    
  </VerticalStackLayout>

</ContentPage>

Base Page .cs:

namespace MauiApp1
{
  public partial class MainPage : ContentPage
  {
    // The child will need access to this variable.
    protected int test = 0;

    public MainPage()
    {
      InitializeComponent();
    }
  }
}

Child Page .xaml:

<?xml version="1.0" encoding="utf-8" ?>
<local:MainPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiApp1"
             x:Class="MauiApp1.NewPage1"
             Title="NewPage1">

  <Label Text="NewPage1 content."/>
</local:MainPage>

Child Page .cs:

namespace MauiApp1;

public partial class NewPage1 : MainPage
{
    public NewPage1()
    {
        InitializeComponent();
    }
}

The Result: the child page's content overriding the base page

As you can see, the child page (NewPage1) has completely overridden the base page's (MainPage) content.

My question is: how can I make the content of both pages be displayed in the manner that I desire, which is the child page replacing only the designated <ContentPresenter/> tag?

EDIT: Forgot to mention that the child page will require access to the base page's views and variables too.


Solution

  • Here's how to implement a reusable BasePage with a custom property

    <!-- BasePage.xaml -->
    <ContentPage
        x:Class="MyMauiDemo.BasePage"
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
        <ContentView.ControlTemplate>
            <ControlTemplate>
                <VerticalStackLayout>
                    <Label Text="{TemplateBinding MainText}" />
                    <ContentPresenter />
                </VerticalStackLayout>
            </ControlTemplate>
        </ContentView.ControlTemplate>
    </ContentView>
    
    // BasePage.xaml.cs
    namespace MyMauiDemo;
    public partial class BasePage: ContentPage
    {
        public static readonly BindableProperty MainTextProperty = BindableProperty.Create(nameof(MainText), typeof(string), typeof(BasePage), default(string));
        public string MainText
        {
            get => (string)GetValue(MainTextProperty);
            set => SetValue(MainTextProperty, value);
        }
        public BasePage()
        {
            InitializeComponent();
        }
    }
    

    And here's how you can use BasePage:

    <!-- MainPage.xaml -->
    <local:BasePage
        x:Class="MyMauiDemo.MainPage"
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:local="clr-namespace:MyMauiDemo"
        TitlePage="MainPage"
        MainText="HELLO WORLD">
        <Label Text="MainPage content." />
    </local:BasePage>
    

    MainPage.xaml.gif

    References: