Manually upgrade a Xamarin.Forms app to a multi-project .NET MAUI app

Upgrading a multi-project Xamarin.Forms app to a multi-project .NET Multi-platform App UI (.NET MAUI) app follows the same steps as a Xamarin.Android and Xamarin.iOS project, with additional steps to take advantage of changes in .NET MAUI.

This article describes how to manually migrate a Xamarin.Forms library project to a .NET MAUI library project. Before you do this, you must update your Xamarin.Forms platform projects to be SDK-style projects. SDK-style projects are the same project format used by all .NET workloads, and compared to many Xamarin projects are much less verbose. For information about updating your app projects, see Upgrade Xamarin.Android, Xamarin.iOS, and Xamarin.Mac projects to .NET, Xamarin.Android project migration, Xamarin Apple project migration, and Xamarin.Forms UWP project migration.

To migrate a Xamarin.Forms library project to a .NET MAUI library project, you must:

  • Update your Xamarin.Forms app to use Xamarin.Forms 5.
  • Update the app's dependencies to the latest versions.
  • Ensure the app still works.
  • Update your project file to be SDK-style.
  • Update namespaces.
  • Address any API changes.
  • Configure .NET MAUI.
  • Upgrade or replace incompatible dependencies with .NET 8 versions.
  • Compile and test your app.

To simplify the upgrade process, you should create a new .NET MAUI library project of the same name as your Xamarin.Forms library project, and then copy in your code, configuration, and resources. This is the approach outlined below.

Update your Xamarin.Forms app

Before upgrading your Xamarin.Forms app to .NET MAUI, you should first update your Xamarin.Forms app to use Xamarin.Forms 5 and ensure that it still runs correctly. In addition, you should update the dependencies that your app uses to the latest versions.

This will help to simplify the rest of the migration process, as it will minimize the API differences between Xamarin.Forms and .NET MAUI, and will ensure that you are using .NET compatible versions of your dependencies if they exist.

Create a new project

In Visual Studio, create a new .NET MAUI class library project of the same name as your Xamarin.Forms library project. This project will host the code from your Xamarin.Forms library project. Opening the project file will confirm that you have a .NET SDK-style project:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
        <TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
        <!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
        <!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
        <UseMaui>true</UseMaui>
        <SingleProject>true</SingleProject>
        <ImplicitUsings>enable</ImplicitUsings>

        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
        <TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
        <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
    </PropertyGroup>

</Project>

In your platform projects, add a reference to this new library project. Then copy your Xamarin.Forms library files into the .NET MAUI library project.

Namespace changes

Namespaces have changed in the move from Xamarin.Forms to .NET MAUI, and Xamarin.Essentials features are now part of .NET MAUI. To make namespace updates, perform a find and replace for the following namespaces:

Xamarin.Forms namespace .NET MAUI namespace(s)
Xamarin.Forms Microsoft.Maui and Microsoft.Maui.Controls
Xamarin.Forms.DualScreen Microsoft.Maui.Controls.Foldable
Xamarin.Forms.Maps Microsoft.Maui.Controls.Maps and Microsoft.Maui.Maps
Xamarin.Forms.PlatformConfiguration Microsoft.Maui.Controls.PlatformConfiguration
Xamarin.Forms.PlatformConfiguration.AndroidSpecific Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific
Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific.AppCompat
Xamarin.Forms.PlatformConfiguration.TizenSpecific Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific
Xamarin.Forms.PlatformConfiguration.WindowsSpecific Microsoft.Maui.Controls.PlatformConfiguration.WindowsSpecific
Xamarin.Forms.PlatformConfiguration.iOSSpecific Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific
Xamarin.Forms.Shapes Microsoft.Maui.Controls.Shapes
Xamarin.Forms.StyleSheets Microsoft.Maui.Controls.StyleSheets
Xamarin.Forms.Xaml Microsoft.Maui.Controls.Xaml

.NET MAUI projects make use of implicit global using directives. This feature enables you to remove using directives for the Xamarin.Essentials namespace, without having to replace them with the equivalent .NET MAUI namespaces.

In addition, the default XAML namespace has changed from http://xamarin.com/schemas/2014/forms in Xamarin.Forms to http://schemas.microsoft.com/dotnet/2021/maui in .NET MAUI. Therefore, you should replace all occurrences of xmlns="http://xamarin.com/schemas/2014/forms" with xmlns="http://schemas.microsoft.com/dotnet/2021/maui".

Note

You can quickly update your Xamarin.Forms namespaces to Microsoft.Maui by using Quick actions in Visual Studio, provided that you have Upgrade Assistant installed.

API changes

Some APIs have changed in the move from Xamarin.Forms to .NET MAUI. This is multiple reasons including removing duplicate functionality caused by Xamarin.Essentials becoming part of .NET MAUI, and ensuring that APIs follow .NET naming guidelines. The following sections discuss these changes.

Color changes

In Xamarin.Forms, the Xamarin.Forms.Color struct lets you construct Color objects using double values, and provides named colors, such as Xamarin.Forms.Color.AliceBlue. In .NET MAUI, this functionality has been separated into the Microsoft.Maui.Graphics.Color class, and the Microsoft.Maui.Graphics.Colors class.

The Microsoft.Maui.Graphics.Color class, in the Microsoft.Maui.Graphics namespace, lets you construct Color objects using float values, byte values, and int values. The Microsoft.Maui.Graphics.Colors class, which is also in the Microsoft.Maui.Graphics namespace, largely provides the same named colors. For example, use Colors.AliceBlue to specify the AliceBlue color.

The following table shows the API changes between the Xamarin.Forms.Color struct and the Microsoft.Maui.Graphics.Color class:

Xamarin.Forms API .NET MAUI API Comment
Xamarin.Forms.Color.R Microsoft.Maui.Graphics.Color.Red
Xamarin.Forms.Color.G Microsoft.Maui.Graphics.Color.Green
Xamarin.Forms.Color.B Microsoft.Maui.Graphics.Color.Blue
Xamarin.Forms.Color.A Microsoft.Maui.Graphics.Color.Alpha
Xamarin.Forms.Color.Hue Microsoft.Maui.Graphics.Color.GetHue Xamarin.Forms property replaced with a method in .NET MAUI.
Xamarin.Forms.Color.Saturation Microsoft.Maui.Graphics.Color.GetSaturation Xamarin.Forms property replaced with a method in .NET MAUI.
Xamarin.Forms.Color.Luminosity Microsoft.Maui.Graphics.Color.GetLuminosity Xamarin.Forms property replaced with a method in .NET MAUI.
Xamarin.Forms.Color.Default No .NET MAUI equivalent. Instead, Microsoft.Maui.Graphics.Color objects default to null.
Xamarin.Forms.Color.Accent No .NET MAUI equivalent.
Xamarin.Forms.Color.FromHex Microsoft.Maui.Graphics.Color.FromArgb Microsoft.Maui.Graphics.Color.FromHex is obsolete and will be removed in a future release.

In addition, all of the numeric values in a Microsoft.Maui.Graphics.Color are float, rather than double as used in Xamarin.Forms.Color.

Note

Unlike Xamarin.Forms, a Microsoft.Maui.Graphics.Color doesn't have an implicit conversion to System.Drawing.Color.

Layout changes

The following table lists the layout APIs that have been removed in the move from Xamarin.Forms to .NET MAUI:

Xamarin.Forms API .NET MAUI API Comments
Xamarin.Forms.AbsoluteLayout.IAbsoluteList<T>.Add The Add overload that accepts 3 arguments isn't present in .NET MAUI.
Xamarin.Forms.Grid.IGridList<T>.AddHorizontal No .NET MAUI equivalent.
Xamarin.Forms.Grid.IGridList<T>.AddVertical No .NET MAUI equivalent.
Xamarin.Forms.RelativeLayout Microsoft.Maui.Controls.Compatibility.RelativeLayout In .NET MAUI, RelativeLayout only exists as a compatibility control for users migrating from Xamarin.Forms. Use Grid instead, or add the xmlns for the compatibility namespace.

In addition, adding children to a layout in code in Xamarin.Forms is accomplished by adding the children to the layout's Children collection:

Grid grid = new Grid();
grid.Children.Add(new Label { Text = "Hello world" });

In .NET MAUI, the Children collection is for internal use by .NET MAUI and shouldn't be manipulated directly. Therefore, in code children should be added directly to the layout:

Grid grid = new Grid();
grid.Add(new Label { Text = "Hello world" });

Important

Any Add layout extension methods, such as GridExtensions.Add, are invoked on the layout rather than the layouts Children collection.

You may notice when running your upgraded .NET MAUI app that layout behavior is different. For more information, see Layout behavior changes from Xamarin.Forms.

Custom layout changes

The process for creating a custom layout in Xamarin.Forms involves creating a class that derives from Layout<View>, and overriding the VisualElement.OnMeasure and Layout.LayoutChildren methods. For more information, see Create a custom layout in Xamarin.Forms.

In .NET MAUI, the layout classes derive from the abstract Layout class. This class delegates cross-platform layout and measurement to a layout manager class. Each layout manager class implements the ILayoutManager interface, which specifies that Measure and ArrangeChildren implementations must be provided:

  • The Measure implementation calls IView.Measure on each view in the layout, and returns the total size of the layout given the constraints.
  • The ArrangeChildren implementation determines where each view should be placed within the bounds of the layout, and calls Arrange on each view with its appropriate bounds. The return value is the actual size of the layout.

For more information, see Custom layouts.

Device changes

Xamarin.Forms has a Xamarin.Forms.Device class that helps you to interact with the device and platform the app is running on. The equivalent class in .NET MAUI, Microsoft.Maui.Controls.Device, is deprecated and its functionality is replaced by multiple types.

The following table shows the .NET MAUI replacements for the functionality in the Xamarin.Forms.Device class:

Xamarin.Forms API .NET MAUI API Comments
Xamarin.Forms.Device.Android Microsoft.Maui.Devices.DevicePlatform.Android
Xamarin.Forms.Device.iOS Microsoft.Maui.Devices.DevicePlatform.iOS
Xamarin.Forms.Device.GTK No .NET MAUI equivalent.
Xamarin.Forms.Device.macOS No .NET MAUI equivalent. Instead, use Microsoft.Maui.Devices.DevicePlatform.MacCatalyst.
Xamarin.Forms.Device.Tizen Microsoft.Maui.Devices.DevicePlatform.Tizen
Xamarin.Forms.Device.UWP Microsoft.Maui.Devices.DevicePlatform.WinUI
Xamarin.Forms.Device.WPF No .NET MAUI equivalent.
Xamarin.Forms.Device.Flags No .NET MAUI equivalent.
Xamarin.Forms.Device.FlowDirection Microsoft.Maui.ApplicationModel.AppInfo.RequestedLayoutDirection
Xamarin.Forms.Device.Idiom Microsoft.Maui.Devices.DeviceInfo.Idiom
Xamarin.Forms.Device.IsInvokeRequired Microsoft.Maui.Dispatching.Dispatcher.IsDispatchRequired
Xamarin.Forms.Device.OS Microsoft.Maui.Devices.DeviceInfo.Platform
Xamarin.Forms.Device.RuntimePlatform Microsoft.Maui.Devices.DeviceInfo.Platform
Xamarin.Forms.Device.BeginInvokeOnMainThread Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread
Xamarin.Forms.Device.GetMainThreadSynchronizationContextAsync Microsoft.Maui.ApplicationModel.MainThread.GetMainThreadSynchronizationContextAsync
Xamarin.Forms.Device.GetNamedColor No .NET MAUI equivalent.
Xamarin.Forms.Device.GetNamedSize No .NET MAUI equivalent.
Xamarin.Forms.Device.Invalidate Microsoft.Maui.Controls.VisualElement.InvalidateMeasure
Xamarin.Forms.Device.InvokeOnMainThreadAsync Microsoft.Maui.ApplicationModel.MainThread.InvokeOnMainThreadAsync
Xamarin.Forms.Device.OnPlatform Microsoft.Maui.Devices.DeviceInfo.Platform
Xamarin.Forms.Device.OpenUri Microsoft.Maui.ApplicationModel.Launcher.OpenAsync
Xamarin.Forms.Device.SetFlags No .NET MAUI equivalent.
Xamarin.Forms.Device.SetFlowDirection Microsoft.Maui.Controls.Window.FlowDirection
Xamarin.Forms.Device.StartTimer Microsoft.Maui.Dispatching.DispatcherExtensions.StartTimer or Microsoft.Maui.Dispatching.Dispatcher.DispatchDelayed

Map changes

In Xamarin.Forms, the Map control and associated types are in the Xamarin.Forms.Maps namespace. In .NET MAUI, this functionality has moved to the Microsoft.Maui.Controls.Maps and Microsoft.Maui.Maps namespaces. Some properties have been renamed and some types have been replaced with equivalent types from Xamarin.Essentials.

The following table shows the .NET MAUI replacements for the functionality in the Xamarin.Forms.Maps namespace:

Xamarin.Forms API .NET MAUI API Comment
Xamarin.Forms.Maps.Map.HasScrollEnabled Microsoft.Maui.Controls.Maps.Map.IsScrollEnabled
Xamarin.Forms.Maps.Map.HasZoomEnabled Microsoft.Maui.Controls.Maps.Map.IsZoomEnabled
Xamarin.Forms.Maps.Map.TrafficEnabled Microsoft.Maui.Controls.Maps.Map.IsTrafficEnabled
Xamarin.Forms.Maps.Map.MoveToLastRegionOnLayoutChange No .NET MAUI equivalent.
Xamarin.Forms.Maps.Pin.Id Microsoft.Maui.Controls.Maps.Pin.MarkerId
Xamarin.Forms.Maps.Pin.Position Microsoft.Maui.Controls.Maps.Pin.Location
Xamarin.Forms.Maps.MapClickedEventArgs.Position Microsoft.Maui.Controls.Maps.MapClickedEventArgs.Location
Xamarin.Forms.Maps.Position Microsoft.Maui.Devices.Sensors.Location Members of type Xamarin.Forms.Maps.Position have changed to the Microsoft.Maui.Devices.Sensors.Location type.
Xamarin.Forms.Maps.Geocoder Microsoft.Maui.Devices.Sensors.Geocoding Members of type Xamarin.Forms.Maps.Geocoder have changed to the Microsoft.Maui.Devices.Sensors.Geocoding type.

.NET MAUI has two Map types - Microsoft.Maui.Controls.Maps.Map and Microsoft.Maui.ApplicationModel.Map. Because the Microsoft.Maui.ApplicationModel namespace is one of .NET MAUI's global using directives, when using the Microsoft.Maui.Controls.Maps.Map control from code you'll have to fully qualify your Map usage or use a using alias.

In XAML, an xmlns namespace definition should be added for the Map control. While this isn't required, it prevents a collision between the Polygon and Polyline types, which exist in both the Microsoft.Maui.Controls.Maps and Microsoft.Maui.Controls.Shapes namespaces. For more information, see Display a map.

Other changes

A small number of other APIs have been consolidated in the move from Xamarin.Forms to .NET MAUI. The following table shows these changes:

Xamarin.Forms API .NET MAUI API Comments
Xamarin.Forms.Application.Properties Microsoft.Maui.Storage.Preferences
Xamarin.Forms.Button.Image Microsoft.Maui.Controls.Button.ImageSource
Xamarin.Forms.Frame.OutlineColor Microsoft.Maui.Controls.Frame.BorderColor
Xamarin.Forms.IQueryAttributable.ApplyQueryAttributes Microsoft.Maui.Controls.IQueryAttributable.ApplyQueryAttributes In Xamarin.Forms, the ApplyQueryAttributes method accepts an IDictionary<string, string> argument. In .NET MAUI, the ApplyQueryAttributes method accepts an IDictionary<string, object> argument.
Xamarin.Forms.MenuItem.Icon Microsoft.Maui.Controls.MenuItem.IconImageSource Xamarin.Forms.MenuItem.Icon is the base class for Xamarin.Forms.ToolbarItem, and so ToolbarItem.Icon becomes ToolbarItem.IconImageSource.
Xamarin.Forms.OrientationStateTrigger.Orientation Microsoft.Maui.Controls.OrientationStateTrigger.Orientation In Xamarin.Forms, the OrientationStateTrigger.Orientation property is of type Xamarin.Forms.Internals.DeviceOrientation. In .NET MAUI, the OrientationStateTrigger.Orientation property is of type DisplayOrientation.
Xamarin.Forms.OSAppTheme Microsoft.Maui.ApplicationModel.AppTheme
Xamarin.Forms.Span.ForegroundColor Microsoft.Maui.Controls.Span.TextColor
Xamarin.Forms.ToolbarItem.Name Microsoft.Maui.Controls.MenuItem.Text Microsoft.Maui.Controls.MenuItem.Text is the base class for Microsoft.Maui.Controls.ToolbarItem, and so ToolbarItem.Name becomes ToolbarItem.Text.

In addition, in Xamarin.Forms, the Page.OnAppearing override is called on Android when an app is backgrounded and then brought to the foreground. However, this override isn't called on iOS and Windows in the same scenario. In .NET MAUI, the OnAppearing() override isn't called on any platforms when an app is backgrounded and then brought to the foreground. Instead, you should listen to lifecycle events on Window to be notified when an app returns to the foreground. For more information, see .NET MAUI windows.

Native forms changes

Native forms in Xamarin.Forms has become native embedding in .NET MAUI, and uses a different initialization approach and different extension methods to convert cross-platform controls to their native types. For more information, see Native embedding.

Bootstrap your migrated app

When manually updating a Xamarin.Forms app to .NET MAUI you will need to enable .NET MAUI support in each platform project, update each platform project's entry point class, and then configure the bootstrapping of your .NET MAUI app.

Enable .NET MAUI in platform projects

Before you update each platform project's entry point class, you must first enable .NET MAUI support. This can be achieved by setting the $(UseMaui) build property to true in each platform project:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    ...
    <UseMaui>true</UseMaui>
  </PropertyGroup>
</Project>

Important

You must add <UseMaui>true</UseMaui> to your project file to enable .NET MAUI support. In addition, ensure you've added <EnableDefaultMauiItems>false</EnableDefaultMauiItems> to your WinUI project file. This will stop you receiving build errors about the InitializeComponent method already being defined.

Add package references

In .NET 8, .NET MAUI ships as a .NET workload and multiple NuGet packages. The advantage of this approach is that it enables you to easily pin your projects to specific versions, while also enabling you to easily preview unreleased or experimental builds.

You should add the following explicit package references to an <ItemGroup> in each project file:

<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />

The $(MauiVersion) variable is referenced from the version of .NET MAUI you've installed. You can override this by adding the $(MauiVersion) build property to each project file:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <UseMaui>True</UseMaui>
        <MauiVersion>8.0.3</MauiVersion>
    </PropertyGroup>
</Project>

Android project configuration

In your .NET MAUI Android project, update the MainApplication class to match the code below:

using System;
using Android.App;
using Android.Runtime;
using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using YOUR_MAUI_CLASS_LIB_HERE;

namespace YOUR_NAMESPACE_HERE.Droid
{
    [Application]
    public class MainApplication : MauiApplication
    {
        public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership)
        {
        }

        protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
    }
}

Also update the MainActivity class to inherit from MauiAppCompatActivity:

using System;
using Microsoft.Maui;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.OS;

namespace YOUR_NAMESPACE_HERE.Droid
{
    [Activity(Label = "MyTitle", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
    public class MainActivity : MauiAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
        }
    }
}

Then, update your manifest file to specify that the minSdKVersion is 21, which is the minimum Android SDK version required by .NET MAUI. This can be achieved by modifying the <uses-sdk /> node, which is a child of the <manifest> node:

<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="32" />

iOS project configuration

In your .NET MAUI iOS project, update the AppDelegate class to inherit from MauiUIApplicationDelegate:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui;
using Foundation;
using UIKit;
using YOUR_MAUI_CLASS_LIB_HERE;

namespace YOUR_NAMESPACE_HERE.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : MauiUIApplicationDelegate
    {
        protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
    }
}

Then, update Info.plist so that MinimumOSVersion is 11.0, which is the minimum iOS version required by .NET MAUI.

UWP project configuration

In your .NET MAUI WinUI 3 project, update App.xaml to match the code below:

<?xml version="1.0" encoding="utf-8"?>
<maui:MauiWinUIApplication
    x:Class="YOUR_NAMESPACE_HERE.WinUI.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:maui="using:Microsoft.Maui"
    xmlns:local="using:YOUR_NAMESPACE_HERE.WinUI">
    <maui:MauiWinUIApplication.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
                <!-- Other merged dictionaries here -->
            </ResourceDictionary.MergedDictionaries>
            <!-- Other app resources here -->
        </ResourceDictionary>
    </maui:MauiWinUIApplication.Resources>
</maui:MauiWinUIApplication>

Note

If your project included resources in your existing App.xaml you should migrate them to the new version of the file.

Also, update App.xaml.cs to match the code below:

using Microsoft.Maui;
using Microsoft.Maui.Hosting;
using YOUR_MAUI_CLASS_LIB_HERE;

namespace YOUR_NAMESPACE_HERE.WinUI;

public partial class App : MauiWinUIApplication
{
    public App()
    {
        InitializeComponent();
    }

    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

Note

If your project included business logic in App.xaml.cs you should migrate that logic to the new version of the file.

Then add a launchSettings.json file to the Properties folder of the project, and add the following JSON to the file:

{
  "profiles": {
    "Windows Machine": {
      "commandName": "MsixPackage",
      "nativeDebugging": true
    }
  }
}

App entry point

.NET MAUI apps have a single cross-platform app entry point. Each platform entry point calls a CreateMauiApp method on the static MauiProgram class, and returns a MauiApp.

Therefore, add a new class named MauiProgram that contains the following code:

namespace YOUR_NAMESPACE_HERE;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>();

        return builder.Build();
    }
}

Note

For Xamarin.Forms UWP projects, the App reference in builder.UseMauiApp<App>() can be found in the MainPage.xaml.cs file.

If there are platform specific services that need to be migrated to .NET MAUI, use the AddTransient(IServiceCollection, Type) method to add a transient service of the specified type to the specified IServiceCollection.

Note

You can quickly update your Xamarin.Forms namespaces to Microsoft.Maui by using Quick actions in Visual Studio, provided that you have Upgrade Assistant installed.

AssemblyInfo changes

Properties that are typically set in an AssemblyInfo.cs file are now available in your SDK-style project. We recommend migrating them from AssemblyInfo.cs to your project file in every project, and removing the AssemblyInfo.cs file.

Optionally, you can keep the AssemblyInfo.cs file and set the GenerateAssemblyInfo property in your project file to false:

<PropertyGroup>
  <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

For more information about the GenerateAssemblyInfo property, see GenerateAssemblyInfo.

Update app dependencies

Generally, Xamarin.Forms NuGet packages are not compatible with .NET 8 unless they have been recompiled using .NET target framework monikers (TFMs). However, Android apps can use NuGet packages targeting the monoandroid and monoandroidXX.X frameworks.

You can confirm a package is .NET 8 compatible by looking at the Frameworks tab on NuGet for the package you're using, and checking that it lists one of the compatible frameworks shown in the following table:

Compatible frameworks Incompatible frameworks
net8.0-android, monoandroid, monoandroidXX.X
net8.0-ios monotouch, xamarinios, xamarinios10
net8.0-macos monomac, xamarinmac, xamarinmac20
net8.0-tvos xamarintvos
xamarinwatchos

Note

.NET Standard libraries that have no dependencies on the incompatible frameworks listed above are still compatible with .NET 8.

If a package on NuGet indicates compatibility with any of the compatible frameworks above, regardless of also including incompatible frameworks, then the package is compatible. Compatible NuGet packages can be added to your .NET MAUI library project using the NuGet package manager in Visual Studio.

If you can't find a .NET 8 compatible version of a NuGet package you should:

  • Recompile the package with .NET TFMs, if you own the code.
  • Look for a preview release of a .NET 8 version of the package.
  • Replace the dependency with a .NET 8 compatible alternative.

Compile and troubleshoot

Once your dependencies are resolved, you should build your project. Any errors will guide you towards next steps.

Tip

  • Delete all bin and obj folders from all projects before opening and building projects in Visual Studio, particularly when changing .NET versions.
  • Delete the Resource.designer.cs generated file from the Android project.

The following table provides guidance for overcoming common build or runtime issues:

Issue Tip
Xamarin.* namespace doesn't exist. Update the namespace to its .NET MAUI equivalent. For more information, see Namespace changes.
API doesn't exist. Update the API usage to its .NET MAUI equivalent. For more information, see API changes.
App won't deploy. Ensure that the required platform project is set to deploy in Visual Studio's Configuration Manager.
App won't launch. Update each platform project's entry point class, and the app entry point. For more information, see Bootstrap your migrated app.
CollectionView doesn't scroll. Check the container layout and the measured size of the CollectionView. By default the control will take up as much space as the container allows. A Grid constrains children at its own size. However a StackLayout enables children to take up space beyond its bounds.
Pop-up is displayed under the page on iOS. In Xamarin.Forms, all pop-ups on iOS are UIWindow instances but in .NET MAUI pop-ups are displayed by locating the current presenting ViewController and displaying the pop-up with PresentViewControllerAsync. In plugins such as Mopups, to ensure that your pop-ups are correctly displayed you should call DisplayAlert, DisplayActionSheet, or DisplayPromptAsync from the ContentPage that's used inside the Mopup popup.
BoxView not appearing. The default size of a BoxView in Xamarin.Forms is 40x40. The default size of a BoxView in .NET MAUI is 0x0. Set WidthRequest and HeightRequest to 40.
Layout is missing padding, margin, or spacing. Add default values to your project based on the .NET MAUI style resource. For more information, see Default value changes from Xamarin.Forms.
Custom layout doesn't work. Custom layout code needs updating to work in .NET MAUI. For more information, see Custom layout changes.
Custom renderer doesn't work. Renderer code needs updating to work in .NET MAUI. For more information, see Use custom renderers in .NET MAUI.
Effect doesn't work. Effect code needs updating to work in .NET MAUI. For more information, see Use effects in .NET MAUI.
SkiaSharp code doesn't work. SkiaSharp code needs minor updates to work in .NET MAUI. For more information, see Reuse SkiaSharp code in .NET MAUI.
Can't access previously created app properties data. Migrate the app properties data to .NET MAUI preferences. For more information, see Migrate data from the Xamarin.Forms app properties dictionary to .NET MAUI preferences.
Can't access previously created secure storage data. Migrate the secure storage data to .NET MAUI. For more information, see Migrate from Xamarin.Essentials secure storage to .NET MAUI secure storage.
Can't access previously created version tracking data. Migrate the version tracking data to .NET MAUI. For more information, see Migrate version tracking data from a Xamarin.Forms app to a .NET MAUI app.

See also