Create your own template
Introduction
If you have some code, that will most likely repeat in several different pages, you might want to make a template from it. You want to make it as convenient as possible, that's why it's important to have constistant templates, that you can easily use just by looking at its code.
Here will be explained creation of 3 files:
Main directory
The very first thing you want to do is create a directory for template in /Templates
.xaml template
First of all, template creation is a bit different from page creation. Two tags are needed as the root:
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="|PathToNamespace|">
<ControlTemplate x:Key="|TemplateName|">
<!-- Content will be here -->
</ControlTemplate>
</ResourceDictionary>
Next, put your page content in it and define changeable content blocks using this:
<ContentPresenter Content="{TemplateBinding |ContentBlockName|}" />
For example you might get this:
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:navigationbar="clr-namespace:PlutoFramework.Components.NavigationBar"
xmlns:txanalyzer="clr-namespace:PlutoFramework.Components.TransactionAnalyzer"
xmlns:password="clr-namespace:PlutoFramework.Components.Password"
x:Class="PlutoFramework.Templates.PageTemplate.Page">
<ControlTemplate x:Key="PageTemplate">
<AbsoluteLayout AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
AbsoluteLayout.LayoutFlags="All">
<Image AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
AbsoluteLayout.LayoutFlags="All"
Source="{AppThemeBinding Light=whitebackground.png, Dark=darkbackground.png}"
Opacity="{AppThemeBinding Light=0.96}"
Aspect="AspectFill"/>
<ScrollView AbsoluteLayout.LayoutBounds="0.5, 0.5, 1, 1"
AbsoluteLayout.LayoutFlags="All"
Padding="0, 55, 0, 0">
<!-- Content block -->
<ContentPresenter Content="{TemplateBinding MainContent}" />
</ScrollView>
<navigationbar:TopNavigationBar Title="{TemplateBinding Title}" />
<txanalyzer:TransactionAnalyzerConfirmationView />
<!-- Popups block -->
<ContentPresenter Content="{TemplateBinding PopupContent}" />
<password:EnterPasswordPopupView />
</AbsoluteLayout>
</ControlTemplate>
</ResourceDictionary>
.xaml.cs file
As the root tag is <ResourceDictionary>
, we can't make a class, that inherits from <ContentPage>
. For that reason there's nothing hard here, just make a dummy class for .xaml:
namespace PlutoFramework.Templates.PageTemplate;
public partial class Page : ResourceDictionary
{
public Page()
{
InitializeComponent();
}
}
TemplateDictionary.xaml
You might've noticed, that there is one file, that isn't in any directory, when you created a directory in /Templates. That's not a mistake, it is a special file, that has a list of all templates in it.
Now you have to add your newly created template, so after that we will continue to creating class for the template.
In file TemplateDictionary.xaml, add namespace of your template and put template in there:
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pagetemplate="clr-namespace:PlutoFramework.Templates.PageTemplate"
x:Class="PlutoFramework.Templates.TemplateDictionary">
<ResourceDictionary.MergedDictionaries>
<pagetemplate:Page />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Here it is added as xmlns:pagetemplate and then Page class used as tag.
.cs file
Moving on to the hardest part: creating class, that will manage our template.
Firstly, make namespace and class:
namespace PlutoFramework.Templates.PageTemplate
{
public class PageTemplate : ContentPage
{
public PageTemplate()
{
}
}
}
Next, to connect the class with template, set ControlTemplate in class' constructor:
namespace PlutoFramework.Templates.PageTemplate
{
public class PageTemplate : ContentPage
{
public PageTemplate()
{
ControlTemplate = (ControlTemplate)Application.Current.Resources["PageTemplate"];
}
}
}
Now, you have to add BindableProperty and configure it for each content block. But first, add alias for Microsoft.Maui.Controls.View, because .net MAUI requires to have View directory, that overwrites it with directory's namespace:
using MauiView = Microsoft.Maui.Controls.View;
Now you can add variable for content and BindableProperty for each content block like this:
public MauiView MainContent
{
get => (MauiView)GetValue(MainContentProperty);
set => SetValue(MainContentProperty, value);
}
public static readonly BindableProperty MainContentProperty =
BindableProperty.Create(nameof(MainContent), typeof(MauiView), typeof(PageTemplate), default(MauiView));
Which leaves us with the following code:
using MauiView = Microsoft.Maui.Controls.View;
namespace PlutoFramework.Templates.PageTemplate
{
public class PageTemplate : ContentPage
{
public MauiView MainContent
{
get => (MauiView)GetValue(MainContentProperty);
set => SetValue(MainContentProperty, value);
}
public MauiView PopupContent
{
get => (MauiView)GetValue(PopupContentProperty);
set => SetValue(PopupContentProperty, value);
}
public static readonly BindableProperty MainContentProperty =
BindableProperty.Create(nameof(MainContent), typeof(MauiView), typeof(PageTemplate), default(MauiView));
public static readonly BindableProperty PopupContentProperty =
BindableProperty.Create(nameof(PopupContent), typeof(MauiView), typeof(PageTemplate), default(MauiView));
public PageTemplate()
{
ControlTemplate = (ControlTemplate)Application.Current.Resources["PageTemplate"];
}
}
}
Now you can add all methods needed and everything needed in constructor, but make sure for ControlTemplate = ...
to be the first in constructor.
And with this, finished code looks like this:
using MauiView = Microsoft.Maui.Controls.View;
namespace PlutoFramework.Templates.PageTemplate
{
[ContentProperty(nameof(MainContent))]
public class PageTemplate : ContentPage
{
public MauiView MainContent
{
get => (MauiView)GetValue(MainContentProperty);
set => SetValue(MainContentProperty, value);
}
public MauiView PopupContent
{
get => (MauiView)GetValue(PopupContentProperty);
set => SetValue(PopupContentProperty, value);
}
public static readonly BindableProperty MainContentProperty =
BindableProperty.Create(nameof(MainContent), typeof(MauiView), typeof(PageTemplate), default(MauiView));
public static readonly BindableProperty PopupContentProperty =
BindableProperty.Create(nameof(PopupContent), typeof(MauiView), typeof(PageTemplate), default(MauiView));
public PageTemplate()
{
ControlTemplate = (ControlTemplate)Application.Current.Resources["PageTemplate"];
// Other calls, not needed in every template
NavigationPage.SetHasNavigationBar(this, false);
Shell.SetNavBarIsVisible(this, false);
}
}
}
Now you can use your very own template - Using already existing templates
Last updated