Migrating a Xamarin lib to MAUI: TaskLoaderView (1/2)

Migrating a Xamarin lib to MAUI: TaskLoaderView (1/2)
https://github.com/roubachof/Sharpnado.TaskLoaderView

Hey hey hey!
Long time no see!
I'm a bit busy with a personal artistic project that will be released later this year...

But hey, I won't miss the MAUI wave \o/

So as you may know, I have several Xamarin.Forms components on GitHub, and some of them are good enough to be worth migration ;)

the TaskLoaderView is my favorite one, I use it in ALL of my apps, cause it makes your app:

  • Fail-safe (no crash)
  • Error feedback-able (no silent errors)
  • So easy to write (no error handling code to duplicate)
  • Consistent from a UI point of view (describe your states in your style dic)

It's also a "pure" XF component, so it's a really good candidate for a first MAUI migration.

For this migration, I used Jetbrains Rider, which is a fantastic IDE.

1. Choose your strategy

Rewrite all

You can chose to just rewrite all your components in .net Maui.
It could be a good idea if you are not happy with your previous code and you don't want to maintain new versions for the 2 platforms.

Share the classes

For the TaskLoaderView, I chose to create a new Maui project, and share all the classes from the regular XF project with the Maui project.
In fact, between XF and Maui, there is very few changes, so you can totally reuse the same code and apply preprocessor directives when there is some discrepancies between the 2 framework.

2. Creating new Maui project

I basically created a new Maui project called Sharpnado.Maui.TaskLoaderView which is just sitting next to my regular Sharpnado.TaskLoaderView XF project.

This project must target .net6 and use maui:

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

    <PropertyGroup>
      <TargetFramework>net6.0</TargetFramework>
      <ImplicitUsings>enable</ImplicitUsings>
      <Nullable>enable</Nullable>
      <UseMaui>true</UseMaui>

...

I also strongly recommend to enable implicit usings as it will ease drastically the migration process.

3. Link all shared files to the maui project

Now you want to add as a link all your files from your Xamarin project.

<ItemGroup>
      <Compile Include="..\Sharpnado.TaskLoaderView\ColorHelper.cs">
        <Link>ColorHelper.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\CompositeTaskLoaderNotifier.cs">
        <Link>CompositeTaskLoaderNotifier.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\DefaultErrorMessageConverter.cs">
        <Link>DefaultErrorMessageConverter.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\Initializer.cs">
        <Link>Initializer.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\InternalLogger.cs">
        <Link>InternalLogger.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\ITaskLoaderNotifier.cs">
        <Link>ITaskLoaderNotifier.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\NotStartedTaskLoaderNotifier.cs">
        <Link>NotStartedTaskLoaderNotifier.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\Snackbar.xaml.cs">
        <Link>Snackbar.xaml.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TaskLoaderCommand.cs">
        <Link>TaskLoaderCommand.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TaskLoaderNotifier.cs">
        <Link>TaskLoaderNotifier.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TaskLoaderNotifierBase.cs">
        <Link>TaskLoaderNotifierBase.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TaskLoaderNotifier{T}.cs">
        <Link>TaskLoaderNotifier{T}.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TaskLoaderView.Updates.cs">
        <Link>TaskLoaderView.Updates.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TaskLoaderView.xaml.cs">
        <Link>TaskLoaderView.xaml.cs</Link>
      </Compile>
      <Compile Include="..\Sharpnado.TaskLoaderView\TimedVisibilityBehavior.cs">
        <Link>TimedVisibilityBehavior.cs</Link>
      </Compile>
    </ItemGroup>

4. Updating dependencies

Well, this one can be tricky.
Imagine your code is depending on another XF library.
Imagine this lib has not been ported to Maui.
Imagine you are $%#%!!.
Fortunately, only dependency TaskLoaderView has is my TaskMonitor which is a netstandard lib with no dependency.

4. Fix the namespaces

After linking the files you will have errors from using Xamarin.Forms namespace:

We could use preprocessor directives to fix those in every of our ui classes. But there is a lazier thing to do: shiming the namespace.

You just have to create an empty Xamarin.Forms.Xaml namespace and the compiler will be happy with it.

You can also see that we have declared 0 maui namespace and the compiler is perfectly fine with it.
It's because of implicit usings.
Implicitly all the maui usings are added globally to the project making our migration so much easy to achieve.

So far we have migrated our projects namespace using 0 preprocessor directives \o/

5. Fix the code

Now, there is still some changes minor changes between XF and Maui.
We can fix those discrepancies with a nice explicit compiler directive: NET6_0_OR_GREATER

Fixing color property names

Adding namespace for AbsoluteLayout flags

Ok I lied, in fact I needed to add one directive to use maui layouts namespace in order to have access to the AbsoluteLayoutFlags enum:

Rectangle => Rect

Some names changed in Maui, it's the case for the Rectangle struct which is now a Rect. The Rectangle name is now reserved for the Maui Shapes.

Casting children views

The Children property of a layout are now of type List<IView> instead of List<View>. So if you want to modify some property like IsVisible you need to cast the item to View.

And that's all the changes I needed to do to the csharp files \o/

6. Fix the xaml

Well this one was a bit disappointing...
All my xaml needed no changes but the maui namespace.
And just for this tiny namespace, I had to copy paste the xaml files instead of linking them... Sad.
I know there is a discussion about xaml preprocess directives:
https://github.com/dotnet/maui/discussions/4096
And it would be so great cause I wouldn't have to copy paste things and just share them, but hey, that's life.

7. Fix the sample project

Well you have to repeat the same strategy for your sample app.
The difference is that the target will include platforms.
Use your favorite ide templates for MAUI application.
Or just use the command line, it's so neat:

And then...stay tuned for the migration of the sample project!