Skip to content

This is a templating system that will allow you to create templates in Xamarin.Forms

Notifications You must be signed in to change notification settings

AutumnEvans418/Evans.XamlTemplates

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Xaml Templates (Work in Progress)

This project is not production ready and just shows how a template system for xaml could work

Reasoning (Why does this exist?)

  • Better reuse of components
  • Inspired by the razor engine in asp.net core.
  • Write less code!
  • Mix C# and xaml to generate your view (think razor)
  • Compatible with current xaml projects.
    • Use as much or as little templates as needed

Additionally, I really hate writing

<StackLayout>
    <Label Text="First Name"/>
    <Entry Text="{Binding FirstName}"/>
    <Label Text="Last Name"/>
    <Entry Text="{Binding LastName}"/>
    <Label Text="Age"/>
    <Entry Text="{Binding Age}"/>
</StackLayout>

over and over again

I'd rather write this:

<local:Entry Caption="First Name" Text="{Binding FirstName}"/>
<local:Entry Caption="Last Name" Text="{Binding LastName}"/>
<local:Entry Caption="Age" Text="{Binding Age}"/>

We can do this by writing this in our Templates.taml file:

@Entry(string Caption, string Text)
{
    <StackLayout>
        <Label Text="@Caption"/>
        <Entry Text="@Text"/>        
    </StackLayout>
}

This will generate the desired control as seen above

How it works

  1. Install the XamlTemplates.MSBuild nuget to your Xamarin.Forms .net standard project
  2. Create a file called Templates.taml
  3. Add the following code @HelloLabel() { <Label Text="Hello World!"/> }
  4. Build the project
  5. This should generate HelloLabel.xaml and HelloLabel.xaml.cs
  6. You can now use this template in you xaml like so: <local:HelloLabel/>

Xaml templates is a templating engine for xamarin forms that allows you to build templates with ease without having to make custom controls.

Turn 40+ lines of code to just 8

Examples

Below is an example of a template in a file called template.taml

Easily use templates in your xaml app Easy to add and update templates, which update the project on build

Basic Example

@LabelEntry(string label,string Text)
{
	<StackLayout>
		<Label Text="@label"/>
		<Entry Text="@Text"/>
	</StackLayout>
}

Result

This will be generated to the following c# and xaml file

LabelEntry.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="Evans.XamlTemplates.LabelEntry">
  <ContentView.Content>
      <StackLayout>
          <Label x:Name="_Label"/>
          <Entry x:Name="_Entry"/>
      </StackLayout>
    </ContentView.Content>
</ContentView>

LabelEntry.xaml.cs

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Evans.XamlTemplates
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class LabelEntry : ContentView
    {
        public static BindableProperty labelProperty = 
            BindableProperty.Create(nameof(label), typeof(string), typeof(LabelEntry), default, BindingMode.TwoWay);
        public static BindableProperty TextProperty = 
            BindableProperty.Create(nameof(Text), typeof(string), typeof(LabelEntry), default, BindingMode.TwoWay);
        public LabelEntry()
        {
            InitializeComponent();
            _Label.BindingContext = this;
            _Entry.BindingContext = this;
            _Label.SetBinding(Label.TextProperty,nameof(label));
            _Entry.SetBinding(Entry.TextProperty, nameof(Text));
        }
        public string label
        {
            get => (string)GetValue(LabelProperty);
            set => SetValue(LabelProperty, value);
        }
        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        } 
    }
}

Third Party Controls

Third party work out of the box

@DataGridSection(string Header, IEnumerable<object> Data)
{
    <syncfusion:SfDataGrid 
        ItemsSource="@Data" 
        AutoGenerateColumns="True" 
        xmlns:syncfusion="clr-namespace:Syncfusion.SfDataGrid.XForms;assembly=Syncfusion.SfDataGrid.XForms"
        />
}

You can also place templates in other templates

@DataGridSection(string HeaderText, IEnumerable<object> Data)
{
    <StackLayout xmlns:local="clr-namespace:Evans.XamlTemplates" xmlns:syncfusion="clr-namespace:Syncfusion.SfDataGrid.XForms;assembly=Syncfusion.SfDataGrid.XForms">
        <local:Header Text="@HeaderText" />
        <syncfusion:SfDataGrid ItemsSource="@Data" AutoGenerateColumns="True"/>
    </StackLayout>
}

More Advanced Example

@EntryAndPicker(string Label,string Text, IEnumerable<string> data, string selectedItem)
{
<StackLayout>
    <Label Text="@Label"/>
    <Entry Text="@Text"/>
    <Label Text="Result:"/>
    <Label Text="@Text"/>
    <Picker ItemsSource="@data" SelectedItem="@selectedItem"/>
    <Label Text="@selectedItem"/>
</StackLayout>
}

Result

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="Evans.XamlTemplates.EntryAndPicker">
  <ContentView.Content>
      <StackLayout>
          <Label x:Name="_Label" />
          <Entry x:Name="_Entry" />
          <Label Text="Result:"/>
          <Label x:Name="_Label1" />
          <Picker x:Name="_Picker" />
          <Label x:Name="_Label2" />
      </StackLayout>
    </ContentView.Content>
</ContentView>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Evans.XamlTemplates
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class EntryAndPicker : ContentView
    {
        public static BindableProperty LabelProperty =
            BindableProperty.Create(nameof(Label), typeof(string), typeof(EntryAndPicker), default, BindingMode.TwoWay);
        public static BindableProperty TextProperty =
            BindableProperty.Create(nameof(Text), typeof(string), typeof(EntryAndPicker), default, BindingMode.TwoWay);

        public static BindableProperty dataProperty =
            BindableProperty.Create(nameof(data), typeof(IEnumerable<string>), typeof(EntryAndPicker), default, BindingMode.TwoWay);
        public static BindableProperty selectedItemProperty =
            BindableProperty.Create(nameof(selectedItem), typeof(string), typeof(EntryAndPicker), default, BindingMode.TwoWay);

        public EntryAndPicker()
        {
            InitializeComponent();
            _Label.BindingContext = this;
            _Entry.BindingContext = this;
            _Label1.BindingContext = this;
            _Picker.BindingContext = this;
            _Label2.BindingContext = this;
            _Label.SetBinding(Xamarin.Forms.Label.TextProperty, nameof(Label));
            _Entry.SetBinding(Xamarin.Forms.Entry.TextProperty,nameof(Text));
            _Label1.SetBinding(Xamarin.Forms.Label.TextProperty, nameof(Text));
            _Picker.SetBinding(Xamarin.Forms.Picker.ItemsSourceProperty, nameof(data));
            _Picker.SetBinding(Xamarin.Forms.Picker.SelectedItemProperty, nameof(selectedItem));
            _Label2.SetBinding(Xamarin.Forms.Label.TextProperty, nameof(selectedItem));
        }

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

        public IEnumerable<string> data
        {
            get => (IEnumerable<string>)GetValue(dataProperty);
            set => SetValue(dataProperty, value);
        }
        public string selectedItem
        {
            get => (string)GetValue(selectedItemProperty);
            set => SetValue(selectedItemProperty, value);
        }
    }
}

Notice how much code it takes to just make a template? There needs to be a simpler solution

Limitations

There are several limitations to Xaml Templates

  • Xaml templates relies on xml linq and doesn't support nested attributes, such as <ContentView.Content>
  • The generated templates may not be optimized. For example, repeating label and entries may be more effecient than placing them in stack layouts.
  • The razor style csharp code is not type checked, meaning if you put supertype test = blah as a parameter, it will generate. Although, your project won't build, so it may still be obvious that the syntax is invalid

Developers

Prerequisite

  • dotnet core 3.1
  • Xamarin.Forms

How to build

Run the build.ps1 script

  • Run the packAndUpdate.ps1 powershell script. This will update the msbuild task and add it to the Evans.XamlTemplates Project
  • Right click solution -> Build Solution

Feature List

  • Allow to nest templates, such as one template calling another
  • Support third party controls, such as syncfusion
  • Default value support for parameters ex. string test = "test"
  • Allow the use of @if statements
  • Support @foreach statements
  • Add example project
  • Create example website
  • Support WPF
  • Support UWP
  • Support Xamarin.Forms
  • Add parameters to MSBuild that can be customized
  • Add generated code warning
  • Add line to the error message
  • Add syntax highlighting for taml files
  • Add ability to generate c# methods and event handling
  • Support Comments
  • Support Xml Dot Attributes
  • Support different base types other than ContentView, such as StackLayout, Grid, etc.

Analysis

What needs to be known?

  • ClassName
  • Parameters (Comma Seperated)
    • Name of Parameter
    • Type of Parameter
  • Controls With Bindings
    • Control Type
    • Control name (Label1, label2, etc...)
    • Bindings on control
      • Control Type
      • Control Property
      • Bindable Property

Logic

foreach parameter
  - create a bindable property
  - create a property
foreach control
  - Set binding context to this
  foreach binding on control
    - set binding for control

Resources

Useful Scripts

In the msbuild task
.\nuget.exe pack .\XamlTemplates.MSBuild.nuspec
You can then add the package using the following command:
dotnet add package XamlTemplates.MSBuild
Note: this works because Nuget.config defines a custom location for the nuget packages

About

This is a templating system that will allow you to create templates in Xamarin.Forms

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published