10+ years of app development
Everything from a single source
50+ successful app projects

Blog

7 steps to migrate from Xamarin.Forms to .NET MAUI

With the end of support for Xamarin approaching in May 2024, developers are busy migrating existing Xamarin.Forms projects to .NET MAUI as its successor. So are we, of course. In this article, I'll show 7 steps we've always had to take during the transition to make your upgrade .NET MAUI easier.

Artikelbild für 7 steps to migrate from Xamarin.Forms to .NET MAUI

Why migrate from Xamarin to .NET MAUI?

With .NET MAUI, Microsoft is modernizing Xamarin Forms into a better cross-platform UI framework that not only brings architectural and implementation changes, but also allows you to move to other target platforms such as Android, iOS, Mac OS (with Mac Catalyst), and Windows. Full support for Samsung's Tizen is also provided.

Is Xamarin and Xamarin Forms dying? If you think of Xamarin as just a product name, yes. Xamarin as a framework will live on as part of .NET MAUI and .NET for Android/ iOS under new names.

Is it possible to use Xamarin in MAUI?

The short answer is no. The long answer is the MAUI team has integrated much of what Xamarin developers know and love about the framework into .NET MAUI and .NET for Android/ iOS. The compatibility mode in .NET MAUI allows you to continue using most of your Xamarin Forms custom renderers and XAML layouts. However, migration is inevitable as many small things like namespaces have changed along with the project structure.

How to migrate or Upgrade Xamarin to .NET MAUI?

With the following 7 steps, we were able to successfully migrate our .NET MAUI projects away from Xamarin.Forms:

You have a migration project? We can save you some time here.

Before you take the migration to .NET MAUI into your own hands, talk to us. Our team of experienced Xamarin developers is looking forward to discussing your project and helping you convert it to .NET MAUI.

Schedule an appointment now

Before starting there are some requirements that should be met:

  • I recommend you to upgrade your Xamarin.Forms app to use at least Xamarin.Forms 5.0 because this version is the closest to MAUI.
  • Android 5.0 (API 21) or higher
  • iOS 10 or higher
  • The complete environment setup for .NET MAUI including all necessary workloads must be installed

Convert all projects to .NET SDK Style for .NET MAUI migration

Microsoft has changed the structure of the project and solution file with .NET Core and continuing. This change has not yet been adopted for Xamarin projects and is now being made up with .NET for Android and .NET for iOS as well as for .NET MAUI. To change your project file, open the Xamarin.Forms project csproj file and customize it according to the following example. For better understanding I have added comments to the most important entries.

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <!-- Specify which platforms should be supported in your app -->
        <TargetFrameworks>net7.0-ios;net7.0-android</TargetFrameworks>
		
        <!-- Distinguishes .NET for Android or iOS from a MAUI project -->
        <UseMaui>True</UseMaui>
        <OutputType>Library</OutputType>
        <ImplicitUsings>enable</ImplicitUsings>

        <!-- Specify which version of a platform should be supported in your app -->
        <SupportedOSPlatformVersion Condition="'$(TargetFramework)' == 'net7.0-ios'">15.4</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="'$(TargetFramework)' == 'net7.0-android'">31.0</SupportedOSPlatformVersion>

        <!-- Required for C# Hot Reload -->
        <UseInterpreter Condition="'$(Configuration)' == 'Debug'">True</UseInterpreter>
    </PropertyGroup>
    <ItemGroup>
        <MauiFont Include="Resources\*" />
    </ItemGroup>
    <ItemGroup>
        <!-- If you used CommunityToolkit -->
        <PackageReference Include="CommunityToolkit.Maui" Version="1.3.0" />
        <!-- Add NuGet-references of your old project file here -->
    </ItemGroup>
</Project>

If you don't want to switch completely to the new "single project" structure at the beginning of the migration, you can keep the existing Android and iOS projects. However, these projects must then also be converted to the SDK style. The structure is the same as above with one minor adjustment - the OutputType value will then change from Library to Exe.

Update NuGet packages

As described before, the NuGet references need to be added. The references to Xamarin.Forms and Xamarin.Essentials are no longer needed.

Now that all package references are combined in one project file, there needs to be a way to distinguish them depending on the platform. To do this, simply add a condition to the ItemGroup for each platform. Using the Google PlayService for Android as an example, this looks like this:

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0-android'">
    <PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.0.2" />
</ItemGroup>

In my experience, it is usually sufficient to change to newer versions for used NuGet packages. Only very old packages for which new versions are no longer available are problematic. In this case it usually helps to look for suitable alternatives or, if it is an open source project, to make the change yourself.

A word about Xamarin.Essentials and Xamarin.CommunityToolkit. While Xamarin.CommunityToolkit is replaced by CommunityToolkit.Maui, Xamarin.Essentials is no longer supported. Replacing Xamarin.CommunityToolkit is an important step in the migration process, as it ensures that the app can continue to use the toolkit's extensions. To use the CommunityToolkit in MAUI, the UseMauiCommunityToolkit method must be added in the MauiApp builder. More about this later in the following section.

Migrate Platform-specific code from Xamarin to MAUI

While in Xamarin.Forms we had platform specific projects, the app was launched with the platform specific code through Xamarin.Forms.Init method. In .NET MAUI, there is a single cross-platform app entry point using MauiProgram.cs. Through this static entry point, a MauiApp instance is created and returned in each supported platform. So, we need to add a new file to the .NET MAUI project (or the old Xamarin Forms project) and name it MauiProgram.cs. .NET MAUI uses the builder principle already known from .NET Core, which leads to the below structure of MauiProgram.cs:

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
        .UseMauiApp<App>()
        .UseMauiCommunityToolkit()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        });

        return builder.Build();
    }
}

Android specific application changes

In order for .NET MAUI to work on Android, three basic changes still need to be made to the old Xamarin Android project.

  1. Update the AndroidManifest.xml by changing the android:targetSdkVersion to 31.
  2. Customize the MainActivity in that it now derives from MauiAppCompatActivity. Remove the OnRequestPermissionsResult method and delete the call of LoadApplication method.
  3. MAUI needs an Android application file which is derived from MauiApplication and overrides CreateMauiApp. If your project doesn't have an application file yet, create a new class and name it MainApplication. See the Bitbucket repository: MAUI-Migration for the exact structure.

iOS specific application changes

Some changes also need to be made in the iOS project.

  1. Update the MinimumOSVersion in your Info.plist to 15.2.
  2. Adjust your AppDelegate that it derives from MauiUIApplicationDelegate.
  3. In your AppDelegate we also need to override CreateMauiApp.
  4. Remove the FinishedLaunching method

You like how we approach things?

This blog is supposed to give you a little insight into our everyday business when we build an app in a full-service-environment or just provide our expertise via Expert-as-a-Service.

Have a look at app development services

Namespace differences between Xamarin.Forms & .NET MAUI

.NET MAUI, like Xamarin.Forms, also uses XAML layouts. You can therefore continue to use your existing XAML layouts with .NET MAUI. To do this, you need to replace the XML namespaces as follows:

  • xmlns="http://xamarin.com/schemas/2014/forms" becomes xmlns="http://schemas.microsoft.com/dotnet/2021/maui".
  • using Xamarin.Forms becomes either using Microsoft.Maui or using Microsoft.Maui.Controls depending of the use case.
  • using Xamarin.Forms.Xaml becomes using Microsoft.Maui.Controls.Xaml.

For performance reasons, the Horizontal and VerticalStackLayout was introduced in MAUI. It replaces the often used StackLayout. You should therefore also invest time and optimize your layouts for this. Please have a look at the Microsoft documentation for more information.

There are also other areas where the namespace has to be adapted. Here are some known API changes you could see while migrating:

  • Colors moved to Microsoft.Maui.Graphics
  • Shapes moved to Microsoft.Maui.Controls
  • BorderColor for Frames does not exists in MAUI
  • Icon for ToolbarItems becomes IconImageSource
  • Image for Buttons becomes ImageSource
  • ForegroundColor for Span does not exists in MAUI

Once you're done with the steps, you can launch the solution in Visual Studio or Visual Studio for Mac. It is very likely that more errors specific to your project will appear, for example from API changes due to newer NuGet package versions or namespace changes, which you will then have to fix step by step.

Typically, there are messages regarding the AssemblyInfo.cs. You can remove them because most of these properties are now csproj-properties. If you want to learn more on how to set these properties, I suggest to read equivalent-to-assemblyinfo-in-dotnet-core-csproj on stackoverflow.

Depending on the complexity and number of errors, in some cases the easiest way is to create a new MAUI project and then add layouts, services and NuGet references. Then, when your project starts, you can start copying your code piece by piece to better locate the source of the error.

Move from Xamarin.Forms Custom Renderer to .NET MAUI Custom Handler

We here at Cayas Software don't know of any Xamarin Forms project in which at least one custom renderer didn't need to be created. Depending on how many are in your project, it's worth converting them to the new handler structure right away. If there are too many after all, you can continue to use your Custom Renderers by updating everything Xamarin.Forms.* related to Microsoft.Maui.* and removing the ExportRenderer directives as they are no longer needed. After that, you still need to enable compatibility mode in MauiProgram.cs via the builder using UseMauiCompatibility().

// shortened
var builder = MauiApp.CreateBuilder();
.UseMauiCompatibility()
.ConfigureMauiHandlers((handlers) =>
{
    handlers.AddCompatibilityRenderer(typeof("Your view"),typeof("Your renderer"));
});

However, I would recommend using the custom handler as it offers better performance and extensibility. In our article on Creating a .NET MAUI Maps Control, we show how you can create a custom handler.

Dependency injection changes in .NET MAUI

In .NET MAUI, it is now much easier to perform dependency injection. MAUI already comes with a container where you can register your services and load them directly into your class using, for example, contructor injection. So you don't need the DependecyService anymore. Just register your service in the MauiProgram.cs as shown below and remove the [assembly: Dependency())] attribute from your service class.

// shortened
var builder = MauiApp.CreateBuilder();
builder.Services.AddSingleton(typeof(BluetoothService));

To get your service into your class, you just need to pass it through the parameters and then you can use it.

public partial class BluetoothSettingsPage : ContentPage
{
    public BluetoothSettingsPage(BluetoothService bluetoothService)
    {
        InitializeComponent();
        var isBluetoothOn = bluetoothService.IsBluetoothOn();
    }
}

You like how we approach things?

You have made it this far, as a developer you have gained an insight into our work. Migrations are just one part of our Xamarin and .NET MAUI work. We support you in all areas of app development.

Let's talk

.NET MAUI project structure updates

To use the new .NET MAUI single project structure, you must perform the following steps. It is optional, but will bring your project closer to the .NET MAUI project structure.

  • In the .NET MAUI or the old Xamarin.Forms project, create a folder called Platforms with a subfolder each for Android and iOS.
  • In the Android folder, copy your Android-specific files such as the Application class, the MainActivity class, the Services, or the Custom-Randerer.
  • To the iOS folder, copy your iOS-specific files such as the AppDelegate class, the Services, or the Custom-Randerer.
  • Also, add a Resources folder to the Maui project if there isn't one already, and copy all the images there.

After that, you can delete your Forms.iOS and Forms.Android projects.

.NET Upgrade Assistant to automate .NET MAUI conversion

Microsoft provides with the .NET Upgrade Assistant a tool that performs many of the steps described here automatically. The advantage of the .NET Upgrade Assistant is that project files, NuGet packages as well as parts of the source code are updated. At the time of writing, however, many places still need to be manually adjusted. Also the Upgrade Assistant only supports C# and Visual Basic which leaves F# (F-Sharp) behind.

To give it a try to see if it works better in your project, two steps are required:

  1. Run the following command in the terminal: dotnet tool update --global upgrade-assistant.
  2. Run the .NET MAUI Upgrade Assistant with the following command: upgrade-assistant upgrade <path to sln or csproj> --non-interactive --entry-point *.

Conclusion

As you can see, migrating a Xamarin.Forms app to .NET MAUI is done in a few steps if you follow the mentioned points. Maybe in the near future the .NET Upgrade Assistant will be able to migrate everything in an automated way and we will have to do very little manual work. Until then, this guide tries to give you a good start. Let me know how your migration went and where there was any problem. I'm sure we'll be able to help you out. You can find the source code in our public Bitbucket repository: MAUI-Migration.

Martin Luong

Martin Luong

With over 7 years of experience in the development of cross-platform apps with Xamarin and .NET MAUI, Martin is one of the old hands at Cayas Software. Customers from the agricultural, logistics and healthcare industries appreciate his calm manner and analytical approach to the implementation of their Xamarin and .NET MAUI projects. He shares some of his daily work with Xamarin and .NET MAUI in his articles.

Related articles

Using voice commands in .NET MAUI
Using voice commands in .NET MAUI

This post is a continuation of the Hackathon topic post, where the technical implementation of voice commands in .NET MAUI is revealed, as well as the challenges the development team faced and how they successfully solved them.

Bidirectional communication with MQTT in .NET MAUI
Bidirectional communication with MQTT in .NET MAUI

As mobile app developer, we constantly have the need to exchange information between the app and the backend. In most cases, a RESTful-API is the solution. But what if a constant flow of data exchange in both directions is required? In this post we will take a look at MQTT and how to create your own simple chat app in .NET MAUI.

Responsive Layouts in .NET MAUI: Master device orientation
Responsive Layouts in .NET MAUI: Master device orientation

.NET MAUI enable us to write platform and device-factor independent apps, which makes it neccessary to adapt dynamically to the users screen size and form. In this blog post you learn how to make your XAML layouts adapt to different device orientations, using a similar syntax to OnIdiom and OnPlatform that you might already be familiar with.