When creating a Xamarin Forms solution with an MVVM framework such as Prism, the view’s backing xaml.cs files are boilerplate. Our application’s logic lives in our view models and ideally their should be no code in the view’s cs file. However if you try deleting them the world breaks and MSBuild has a tantrum.

Enter C# Source Generators

A Source Generator is a piece of code that runs during compilation and can inspect your program to produce additional files that are compiled together with the rest of your code.

Prerequisites

  • You can follow the announcement blog post here to get setup
  • Install the latest .NET 5 preview and the latest Visual Studio preview. (Don’t skip the intro and forget this part like I did)
  • A Xamarin Forms solution

Just want to see working code

Source code generators are created as a .NET Standard library project so first thing we need to do is add a new .Net Standard Library project to our existing Xamarin Forms Solution.

ViewGenerator is the .Net Standard Library we’ve added in

We now need a single class which will contain our generator. Within the execute method we create a loop and we loop over a list of views we want to create backing files for. We pass in the file name to create the class and the constructor. Ideally we would want to automatically discover the views within our project but I couldn’t work out how to extract that information from the SourceGeneratorContext so for now they are just listed in the generator.

using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace ViewGenerator
{
  [Generator]
  public class ViewGenerator : ISourceGenerator
  {
    public void Execute(SourceGeneratorContext context)
    {
      // begin creating the source we'll inject into the users compilation
      StringBuilder sourceBuilder = new StringBuilder();

      // we need to somehow discover the views in a project automatically - for now they listed here
      var views = new List<string>();
      views.Add("MainPage");
      views.Add("SecondPage");

      foreach (var view in views)
      {
        sourceBuilder.Append($@"
        
        using Xamarin.Forms;
        namespace PrismExample.Views
        {{
          public partial class {view}
          {{
            public {view}()
            {{
              InitializeComponent();
            }}
          }}
        }}

        ");
      }


      // inject the created source into the users compilation
      context.AddSource("viewGenerated", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
    }

    public void Initialize(InitializationContext context)
    {
      // No initialization required
    }
  }
}

With our generator complete we can now reference it from our Xamarin Forms shared project. Thanks to some clever people on Twitter this part has been simplified greatly. Add the following reference to your csproj, and while you are in the csproj file make sure your LangVersion is set to preview.

  <ItemGroup>
    <ProjectReference Include="..\..\ViewGenerator\ViewGenerator.csproj" 
                      OutputItemType="Analyzer"
                      ReferenceOutputAssembly="false" />
  </ItemGroup>

Finally we can go through our views folder and delete all the .xaml.cs files. Now every time we build the project these files will be automatically added to the compiled source and our solution explorer can stay nice and clean!