App Development Xamarin: Xamarin.Forms to .NET MAUI

Methods to the Madness

Posted by davidpuplava on September 06, 2022

Purpose

The goal of this post is to journal my migration of a long standing Xamarin.Forms app to using .NET MAUI.

Background

As a programmer, one of my many personal pet projects is a mobile app that allows you to create little games to play on your mobile device and share with friends. Not suprising to fellow programmers, I've been working on this application for a long time. About nine (9), yes nine, years. In that time, I've had to update and migrate the code base a few times to keep up with the times and the technology.

My preferred platform and language is .NET C# - I use it for my day job and it's what I know best. I have experience writing mobile apps for iOS and Android using their native languages. I even have experience using hybrid frameworks such as Cordova for cross platform development.

Nonetheless, I fell in love with Xamarin years ago before they were acquired by Microsoft and was over the moon with using C# to write crossplatform application and have them natively compile to their respective platforms. I have the scars to prove how brutal the tooling was, how mind numbing the troubleshooting was, and how frustrating it was to wait for the build process to complete only to find out there was an error. Or worse, seeing a runaway build that never ended only having to reboot to get the build to complete.

Fast forward to today, where I once again must embark on a journey to upgrade my toolset and migrate my code base. Long story short, I have a Mac mini M1 which has an arm processor. I have to use Visual Studio for Mac 2022 and .NET 6. As such I have to migrate my code base from .NET 5 to .NET 6. This includes migrating from Xamarin.Forms to .NET MAUI.

Let the games begin.

Current State

To avoid the nitty gritty details, I'll speak in overly simplified terms. So if something doesn't make sense let me know.

I have a multi-project solution that contains the following kinds of projects

  • .NET MVC Web application
  • .NET Standard 2.1 shared library project that references Xamarin.Forms 5.0
  • Xamarin.iOS project
  • Other shared library projects written from scratch
  • Other 3rd party library projects from Nuget.org

The Original Problem

Skipping a lot of detail, I use Visual Studio for Mac for development. I have a Mac mini M1 and because of the ARM processor I have to using Visual Studio for Mac 2022. The problem is I can't compile my code base because .NET 5.0 is not supported in Visual Studio for Mac 2022. I have to upgrade to .NET 6.

I tried to just modify the target frameworks in the Xamarion.iOS project, but I received the following error when compiling.

Path Forward

I used the following guide to do the migration: https://github.com/dotnet/maui/wiki/Migrating-from-Xamarin.Forms-(Preview).

Following the advice in the guide above, I ensure that I had the correct toolset installed, which I thought I did but turns out I didn't.

At the time of this writing, I have Visual Studio for Mac Preview - Version 17.4 Preview (17.4 build 715).

The guide recommends you create and run a blank MAUI project to make sure your tooling is correctly setup. When I first tried this I got a compiler error about Android components not being found. I installed these tools and then the default blank MAUI compiled and ran fine.

Now that I know I have MAUI installed correctly, it's time to start migrating my Xamarin project to use MAUI.

Migration from Xamarin to .NET MAUI

In general, the migration went well. I screwed up a couple of things. The documentation has you find and replace a number of using statements which I did in the order they listed in the documentation. The problem is that one of the replacements actually makes it difficult to do the last replacement.

Specifically, when I did a find on

using Xamarin.Forms

and replaced it with

using Microsoft.Maui;
using Microsoft.Maui.Controls;

I inadvertantly replaced all of the following strings as well.

using Xamarin.Forms.Xaml

So I was left with using Microsoft.Maui.Xaml which is not a valid namespace.

Luckily, I could easily replace it.

The next several compile errors dealt with unknown types and were easily fixed by using Visual Studio's suggestions on types to reference.

Another error that was trickier was that I had a problem with the .NET Standard 2.1 library referenced by .NET 6. The specific error I received was that the .NET MAUI project that referenced the .netstandard 2.1 project could not actually find the .netstandard2.1 dll when compiling. On a hope and a prayer, I checked all of the library projects in my solution and found that some of them targeted .netstandard2.0 which I thought might be tricky for the compiler. No reason to target 2.0 so I target .netstandard 2.1 and this resolved my error.

Fixing AppShell.xaml

The next set of compiler errors I encounter is related to the AppShell.xaml file. Something similar to the following.

Microsoft.Maui.Controls.SourceGen/Microsoft.Maui.Controls.SourceGen.CodeBehindGenerator/AppShell.xaml.sg.cs(34,74,34,86): error CS0103: The name 'CommonStates' does not exist in the current context

Closer inspection of the AppShell.xaml file and I see a lot of errors.

Mousing over the tip, I note that Shell can't be found and realize that the xmlns attribute says Xamarin and this probably isn't right. I recall from the migration guide that I have to update the namespaces of all my .xaml files. I look and see that I am terrible at following directions. None of the xamlns entries were replaced. Or more precisely, I accidently replaced them with a copy of themselves. After I did a find/replace changing them I got rid of the compiler error and came across new errors related to the contents of the .xaml files themselves which is what I expected.

Xaml, Fix all the Xaml

I had to replace OSAppTheme.Dark with AppTheme.Dark (and .Light, respectively).

I had to replace Xamarin.Forms.Device.RuntimePlatform with DeviceInfo.Current.Platform which is in the Microsoft.Maui.Devices namespace.

The next challenge was the Error: XLS0414: The type 'DynamicResource' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.. Interestingly enough, closing and then restarting Visual Studio resolved this error.

Rebuilding lead to fewer errors.

Had to change <ToolbarItem Name="..." to <ToolbarItem Text="...".

I had to complete remove the following.

xmlns:iOS="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
iOS:NavigationPage.IsNavigationBarTranslucent="False"

Had to remove this too.

xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.UseSafeArea="true"

And after a few other compiler errors for XAML namespaces I wasn't even using, I successfully compiled my new .NET MAUI project that was migrated from Xamarin.Forms.

About the Author: David Puplava

David Puplava is a professional C# developer and consultant with over 15 years of experience. He has designed and implemented several custom, enterprise software systems across the election, law enforcement and energy industries. You can learn more about David from his personal blog https://www.davidpuplava.com or follow him on Twitter @davidpuplava.