You are on page 1of 56

Migration to .

NET MAUI
When and How to Transition
to Cross-Platform App Development
EBOOK
Table of Contents
Introduction / 4 Part 3: Migration of Xamarin ERP App to
.NET MAUI / 15
Part 1: Should You Migrate from Xamarin. 1. Run the Dotnet Upgrade Assistant / 15
Forms to .NET MAUI? When? / 4 2. Create a Blank .NET MAUI App / 16
The Benefits of Migrating to .NET MAUI / 5 3. Add Third-Party References / 16
Easier Development and Benefits for the Team / 5 4. Move Independent Code / 18
1. .NET MAUI Is Part of .NET / 5 Login and Authentication / 18
2. Better Tooling / 5 5. Pages and Themes, or the XAML Part / 19
3. Frequent Upgrades and Addressing Developer Base Classes and Data Context / 19
Feedback / 6 Raplacing Telerik UI / 19
4. Command Line Support / 6 6. Consider the Images / 20
5. Simple Project Structure / 6 7. ViewModels / 21
6. Better Customization / 6 8. AuthenticationService and NavigationService / 22
7. Better Handling of Resources in .NET MAUI / 7 Register the Services / 23
8. Inclusion of Graphics / 8 9. Migrating Datamodels and Services / 24
9. Unification of Libraries / 8 11. MauiSplash Screen & Icon / 27
10. Modern Patterns / 8 Conclusion / 28
Benefits for the App / 9
11. Continuous Performance Improvements / 9 Part 4: How to Migrate Xamarin.Forms
12. Better Accessibility Support / 9 Renderers to .NET MAUI Handlers? Should
13. Multiple Windows and More to Expect / 9 We? / 28
14. Desktop & Blazor Support Is Also Important / 9 What Are the Options? / 29
Are There Any Cons if I Migrate? / 10 So, How to Choose? / 29
Is .NET MAUI Mature Enough for a Production App / 10 Option 1: Continue to Use the Same Renderers / 29
Is There Any Risk if I Do Not Migrate or Delay 1. Move the Files to the Right Place / 30
Migration? / 11 Xamarin.Forms vs. .NET MAUI files / 30
2. Modify the Code a Little Bit / 30
Part 2: Things to Consider When Planning 3. Register the Renderers / 31
Your Migration from Xamarin.Forms to .NET Option 2: Using Handlers and Mappers / 32
MAUI / 12 What Are These Handlers? / 32
1. Install VS 2022 and Set up Your .NET MAUI What Are Mappers? / 32
Environment / 12 Scenario 1: Access the Handler When You Need
2. Review Data Models and Patterns of Your Existing to Modify It / 33
App / 13 Scenario 2: Use Handler Lifecycle Events to Access It and
3. Choose a Navigation Pattern / 13 Modify Properties of the Components / 34
4. Check Whether Your Third-Party Libraries Support .NET Scenario 3: Create a Custom Component and a New
MAUI / 14 Handler / 34
5. Azure Support / 14 Conclusion / 34
6. Take a Minute to Consider the Future of Windows
Support / 14
7. Have You Used Custom Renderers to Customize the
Native Controls? / 15

2 © 2023 Progress. All Rights Reserved.


Part 5: Practical Tips for Migrating from Part 6: .NET MAUI vs Blazor Hybrid / 40
Xamarin to .NET MAUI / 35 Which One to Use? / 41
Tip for Starting: Use Upgrade Assistant and a Blank New Transform a WPF App to Cross-Platform with
Project / 35 .NET MAUI / 41
Tip for Namespaces: Use XAML Schemes When .NET MAUI XAML vs. WPF XAML / 41
Possible / 36 Using Text / 42
Tip for Azure Mobile Services / 37 Using Borders / 42
Tip for Checking the Device: Use the New DeviceInfo and Height/Width vs. RequestHeight/RequestWidth / 42
DevicePlatform Classes / 37 Layouts / 43
A Simple Example of Replacing the Code / 37 Using Windows / 44
Tip If Using Microsoft ListView: Replace ListView with Events / 45
CollectionView / 38 Images & Resources / 46
Tip for Colors: With Two New Classes, CommunityToolkit. Customization / 46
Maui Is Here to Help / 38 What to Know When Porting a WPF App to Blazor
Layout Behavior Changes from Xamarin.Forms / 39 Hybrid / 48
Is .NET MAUI Always the Answer? / 39 Scenario 1 / 48
Scenario 2 / 49

Conclusion / 55
About The Author / 56
Rossitsa Fakalieva / 56

3 © 2023 Progress. All Rights Reserved.


Introduction
Mobile apps are so essential for businesses that, for a while, we experienced the heyday
of mobile-first application development. But our industry seems to be steadily moving in
the direction of cross-platform development as users and customers demand connected
digital experiences that are convenient for them in every way imaginable.

Cross-platform also brings the promise of numerous benefits for the developer experience.
Improved performance, single code base compatible with various platforms, easy
deployment—all enticing perks that will save you development time worth countless
human hours.

So, what if you have your business apps built with Xamarin? Should you upgrade to .NET
MAUI and, if so, when? If you have a stable app and are not planning to add updates to it,
you may be years aways from the point that requires you to plan a migration.

But what if your app does need an update right now? This guide will help you examine the
benefits of migrating to .NET MAUI from Xamarin.Forms for the dev experience, the app
and its end users, plus any downsides, so you can decide if and when migration is right for
your app.

Part 1: Should You Migrate


from Xamarin.Forms to
.NET MAUI? When?
.NET MAUI is the new hot dotnet technology, but should we consider migrating our
existing app right away or is it better to hold on with this decision? This is a question that
every good PM, team lead and software engineer asks themselves when such a trend
appears.

I want to explore the right way to decide whether migration from Xamarin.Forms to .NET
MAUI is the right path for your code, team and application and whether you should
consider it.

4 © 2023 Progress. All Rights Reserved.


The Benefits of Migrating to .NET
MAUI
.NET MAUI is a successor of an already existing technology—Xamarin.Forms—so it is
designed to improve weaknesses and add more benefits when we are talking about
the development of cross-platform apps. There are benefits for both the development
experience and the end result. Let’s review all of them:

Easier Development and Benefits for the Team


I will start with the most important part for every developer—the performance and
the experience of the development process. With .NET MAUI, this is way easier than
development with Xamarin.Forms. Let’s see why:

1. .NET MAUI Is Part of .NET

This is the major change—the architecture of the new framework is designed by Microsoft
with the main goal of being integrated into .NET and simply being better than Xamarin.
Forms.

.NET Multi-platform App UI (.NET MAUI) is integrated into .NET, while Xamarin is not,
although it is still part of .NET Core 3.1. So, due to the integration of .NET 6, 7 and 8, you
can use the new C# and .NET features in .NET MAUI for your enterprise development.

Starting with .NET 7, .NET MAUI will align with the .NET release cadence—that is, .NET
MAUI 7.0 will ship with .NET 7.0, .NET MAUI 8.0 ships with .NET 8.0, and so on.

2. Better Tooling

VS 2022 and VS 2022 for Mac install the MAUI workloads directly and take care of the
smooth dev experience. Coming as part of VS installer, installing and updating .NET MAUI
is way easier for engineers.

With VS 2022, there are also AI-assisted code suggestions like IntelliCode, which gives
developers a powerful set of automatic code completions that understand the .NET MAUI
app UI and code. When a dev starts typing, it will understand the code context, variable
names, functions, and even provide better IntelliSense and suggest whole line completions.

5 © 2023 Progress. All Rights Reserved.


Other tools that speed up the development process are:
• XAML Live Preview – allows you to preview code changes in real time.
• XAML Hot Reload – change the UI and see the result in the running app with your
real data right away.
• · .NET Hot Reload – the ultimate tool that you can use to make changes to your code,
save and see those changes without losing your application state.

3. Frequent Upgrades and Addressing Developer Feedback

Currently, .NET MAUI is one of the key technologies that Microsoft is focused on and
there are a lot of channels that MS is using to gather feedback and address it. This is great
because if there is something you do not like, you have power as a developer to let them
know—write feedback or contribute to the repo, which is very active.

4. Command Line Support

Another advantage of using .NET MAUI is that it runs on .NET CLI. The .NET command-
line interface (CLI) is a cross-platform toolchain for developing, building, running and
publishing .NET apps.

5. Simple Project Structure

Honestly, this is my favorite. If you have ever used Xamarin.Forms, you probably know that
it uses separate projects for each target platform. With .NET MAUI, you will no longer have
this problem as here all the platforms can easily be managed in a single project. To create
a .NET MAUI project, you can find all necessary features like fonts, app icons, images,
styling, raw assets and splash screen in the Resources folder. .NET MAUI will do the rest by
optimizing them for each platform’s specific requirements.

This also makes it easier to share not only resources but tests too.

6. Better Customization

.NET MAUI is coming with a completely new architecture. It has two main purposes—
performance optimizations and decoupling of custom code from the native UI. With
this change, it’s easier to add support of new platforms even when they need custom
experience.

6 © 2023 Progress. All Rights Reserved.


Let’s try to explain this further:

.NET MAUI introduces a new abstract layer of control interfaces. And a new concept, called
Handlers, which depend only on interfaces, but not on the implementation of UI controls:

Xamarin. Forms. Entry Entry Renderer iOS

Entry Renderer Android

Figure 1: Xamarin.Forms implementation of renderers’ architecture

partial class

Maui. Controls. Entry IEntry Entry Handler

EntryHandler.ios.cs

EntryHandler.android.cs

platform-specific

Figure 2: .NET MAUI implementation of handlers’ architecture

To customize the behavior, we can now write our own handler classes and mappers instead
of renderers.

This makes the developer’s life easier—we can easily modify the handler to exclude/
include more platforms. This is a great feature having in mind that adding a new OS is
always an option.

7. Better Handling of Resources in .NET MAUI

With .NET MAUI, we can manage the resources more easily too. As a result of the SDK
style project, there is a folder named Resources, under which SVG images are included and
used as the image source and splash screen.

7 © 2023 Progress. All Rights Reserved.


In .NET MAUI, resource files can be tagged into various categories based on the role they
play in the project using BuildAction. You can use the table below for reference:

Resource Type BuildAction Tag


App icon MauiIco
Images MauiImage
Spash Screen Image MauiSplashScreen
Fonts MauiFont
Style definition using external CSS MauiCss
Raw Assets MauiAsset
XAML UI definition MauiXaml

8. Inclusion of Graphics

In Xamarin.Forms, you cannot find any direct APIs for drawing graphics. However, with
.NET MAUI, the situation is different: its cross-platform graphics functionality offers a
drawing canvas for painting and drawing shapes. Graphics modes such as paint, winding
and blend are available. A nice scenario is also the better approach for handling images
with Graphics.

9. Unification of Libraries

.NET Multi-platform App UI now includes a lot of open-source APIs as Xamarin.Essentials


is directly integrated into MAUI, enabling access to features like contacts, photos, device
sensors, secure storage, authentication and other services.

10. Modern Patterns

.NET MAUI is also one step closer to other modern frameworks introducing MVU and RxUI
support together with one of developers’ favorites—the MVVM pattern.

8 © 2023 Progress. All Rights Reserved.


Benefits for the App
Now it’s time to review the possibilities that the new platform brings to the application to
make it more attractive to end users—and even attract new users!

11. Continuous Performance Improvements

The Microsoft teams developing the .NET stack are focused on improving performance.
They are committed to this, and .NET MAUI is no exception to this rule. MS improved the
performance by introducing the new architecture and the handlers concept, but the .NET
MAUI team is also committed to continuing improvements in this area. Read more about
.NET MAUI performance here.

12. Better Accessibility Support

With Semantic properties, developers can define information about which controls should
receive accessibility focus and which text should be read aloud to the user. Semantic
properties are attached properties that can be added to any element to set the underlying
platform accessibility APIs. This will make your .NET MAUI app more accessible compared
to its Xamarin.Forms version.

13. Multiple Windows and More to Expect

This is just one of the recent features that Microsoft added to .NET MAUI, which was
really missed and needed for desktop behavior. This again shows the commitment to the
development of this framework and that it is here to stay.

14. Desktop & Blazor Support Is Also Important

Targeting MacOS and Windows desktop users for real, .NET MAUI is not just a mobile
framework that runs on Windows, but a cross-platform framework focused on the desktop
experience. Multi-windows, context menus and many more features are added to .NET
MAUI to allow this.

With Blazor and .NET MAUI Blazor Hybrid apps, you can really extend your existing code
to fit your needs—you can reuse Blazor code and offer a real desktop experience with
unified UI to all devices as Blazor components are able to access native APIs from code
behind!

9 © 2023 Progress. All Rights Reserved.


Are There Any Cons if I Migrate?
The short answer is no—.NET MAUI is the successor of Xamarin.Forms so it is simply
better. However, there are some things to consider before making the final decision.

1. There are some unsupported platforms such as WPF, UWP and Android versions less
than 21. They are unsupported for a reason—Windows support now relies on WinUI and
the Android version is quicky increasing.

See the table for details:

Platform Xamarin.Forms Platforms .NET MAUI


Android API 19+ Android API 21+
iOS 9-15 iOS 10+
Windows (UWP) Windows (via WinUI)
MacOS (via MacCatalyst) – Microsoft
MacOS – community support support
Blazor
Tizen Tizen
WPF

2. There is also a learning curve during the migration, but we are here to help—the
following chapters in this guide should help you understand how you can handle the
learning curve.

3. And, of course, consider the time cost. Should you use the time of your team for
migration or for developing new features of the existing Xamarin.Forms app? There is no
right answer here as this depends on your app, but I hope this guide will help you estimate
the migration time and possibly speed it up.

Is .NET MAUI Mature Enough for a


Production App?
.NET MAUI is an official technology stack now. It shipped with .NET 6, and the issues
typical for a new tech were addressed in .NET 7. New capabilities continue to be added
with .NET 8., some of which you can already see in the preview version.

10 © 2023 Progress. All Rights Reserved.


.NET 7 and VS 2022 provide us with a stable version of the framework. Also, Microsoft
documentation and the resource hub provide us with a lot of resources that we can use.
The .NET MAUI repo is active, and developer feedback is considered in a good amount of
time.

Another important area to this matter is the fact that a lot of third-party APIs, such as
Progress® Telerik®, now provide their version supporting .NET MAUI.

All of these make .NET MAUI not just a good choice for a production app, but a “must-do”.

Is There Any Risk if I Do Not Migrate


or Delay Migration?
Xamarin.Forms support will end on May 1, 2024, and although there is a year ahead at the
time of writing this guide, it is not prudent to wait until the last moment. Start now and
have enough time to safely migrate your app and even consider expanding it with desktop
and web support.

As a conclusion, I believe the natural path of every Xamarin.Forms app is .NET MAUI, but
the final decision is yours.

If you decide to migrate, we will now go into more detail about how to migrate your
current Xamarin.Froms app based on a Progress Telerik demo application.

11 © 2023 Progress. All Rights Reserved.


Part 2: Things to Consider
When Planning Your
Migration from Xamarin.
Forms to .NET MAUI
What steps should you take when preparing to migrate your app from Xamarin.Forms to
.NET MAUI? This list will help you think it through.

In short, these are the things that are good to consider before starting:
• Prepare your environment
• Review DataModels
• Choose a navigation pattern
• Analyze third-party libraries
• Benefit from Azure support
• Take a minute to think about Windows UI and the desktop experience
• Leave customization until the end

1. Install VS 2022 and Set up Your


.NET MAUI Environment
This is a basic but very important step for our process. Installing the latest version of VS
2022 or VS for Mac should set up most of what you need to start your development. Still,
for Mac there are some additional requirements, such as:

• A Mac that is compatible with the latest version of Xcode. For more information, see
Apple’s minimum requirements documentation.

• The latest version of Xcode.

• An Apple ID and paid Apple Developer Program enrollment. An Apple ID is required


to deploy apps to devices, and to submit apps to the Apple Store.

Note: The full list of prerequisites can be found on Microsoft’s documentation site—check
it out for the latest updates.

12 © 2023 Progress. All Rights Reserved.


Once you are ready, you will be able to start with a basic .NET MAUI app. Create one and
have a look at it as we will use it as a reference during the migration.

Another important tool that we will use during the migration is .NET Update Assistant. You
can download it too from VS MarketPlace, but I still recommend you use it via cmd as the
extension has some limitations. You can install it with the following command:

dotnet tool install -g --add-source “https://api.nuget.org/v3/index.

json” --ignore-failed-sources upgrade-assistant

2. Review Data Models and Patterns


of Your Existing App
Now is a good time to review how the code separation is handled in your app and decide
whether to migrate it directly or consider changing it as .NET MAUI support improved
MVVM support and a new MVU pattern is also added.

If you’re already using MVVM in your app, it is more natural to stay on it. It’s a great
and widely used pattern. But if this is the case, there are some other important notes to
consider if you use one of the popular MVVM helper libraries:

MVVM cross is popular for Xamarin, but currently not supported with .NET MAUI. As an
alternative, you can rely purely on the built-in MVVM MAUI support or consider using the
MVVM Community toolkit.

3. Choose a Navigation Pattern


.NET MAUI supports great shell navigation, and every sample .NET MAUI app contains
a template ready to start with. If you do not use shell navigation, consider this change
as a step in the migration plan: .NET MAUI Shell navigation - .NET MAUI | Microsoft
Learn. Using basic page navigation is also an option: FlyoutPage, TabbedPage and
NavigationPage.

13 © 2023 Progress. All Rights Reserved.


4. Check Whether Your Third-Party
Libraries Support .NET MAUI
This is a critical step in your preparation. Check this in advance and find alternatives of
your APIs if they don’t support .NET MAUI.

One such library is Progress® Telerik® UI for Xamarin and you’ve used it in your apps—
don’t worry—you can safely replace it with Telerik® UI for .NET MAUI.

5. Azure Support
Where is your data service published? What kind of login authentication do you have?
Take a moment to consider the usage of Azure for all of these if you still haven’t.

If your mobile version already uses Azure, an important note is that Microsoft.
WindowsAzure.MobileServices are now rebranded as Microsoft Datasync.Client. Read
a full explanation and get a sample in Microsoft’s docs: Build a .NET MAUI app with Azure
Mobile Apps | Microsoft Learn. We will revisit this topic again in one of our next chapters
where we integrate a Telerik UI for .NET MAUI-built app and Azure mobile.

So, plan the migration of Azure references as a separate step and read the relevant
resources before that.

6. Take a Minute to Consider the


Future of Windows Support
With .NET MAUI Windows, support is focused more on the desktop side. This means you
need to consider whether you want to polish the UI of the Windows version to be a little
better for your desktop users. If Windows is not a priority for you, you can still leave this
part for debugging and easy development purposes.

14 © 2023 Progress. All Rights Reserved.


7. Have You Used Custom Renderers
to Customize the Native Controls?
Consider their migration to .NET MAUI handlers by preparing yourself with handler
architecture—should we use the handlers architecture or migrate the renderers directly?

There are some API changes when migrating from Xamarin.Forms to .NET MAUI. We will
review them in the next two chapters, explaining how we managed to migrate an ERP app.

Part 3: Migration of
Xamarin ERP App to .NET
MAUI
Now it’s time to do the “dirty” job and actually migrate a real app. I’ve taken a complex real-
world app—Telerik Xamarin ERP—built with Telerik UI components.

The solution itself contains two major projects—web service telerikErpService.sln and
Xamarin.Forms app TelerikErp.sln. Let’s leave the service for now as it is a general .NET
app and focus on the Xamarin part.

The steps that I followed to port the app are:

1. Run the Dotnet Upgrade Assistant


I started using the dotnet Upgrade Assistant with the following command:

C:\Users\Rosit\Documents\ERP> upgrade-assistant upgrade C:\Users\

Rosit\Documents\ERP\app|ErpApp.sln --non-interactive

The tool will back up the app, convert it to .NET 7, rename the Microsoft.Namespaces. with
the Microsoft.Maui and Microsoft.Maui.Controls namespaces.

15 © 2023 Progress. All Rights Reserved.


These changes are great, but the assistant will not update any third-party reference and
will not deal with the UWP project, so a lot of manual changes will still be required.

2. Create a Blank .NET MAUI App


That is why I decided to start with a blank new .NET MAUI app and copy the cs and xaml
files step by step from the output of the UpgradeAssistant in the order described later
here.

3. Add Third-Party References


The Telerik ERP app uses the following third-party packages that we need to replace with
their .NET MAUI alternative:
• Telerik UI for Xamarin
• MVVM cross
• Azure Mobile Client services

For the UI part, it is easy—now we will use Telerik UI for .NET MAUI, the UI suite that is
identical to the one we have built the ERP with—just supporting the framework we need.
You can download it here or directly as a NuGet from Telerik NuGet Server.

MVVM Cross does not support .NET MAUI, but the good news is that .NET MAUI itself
gives us all we need to replace it. Still, to make the migration easier, I will use the MVVM
Community toolkit, which gives me similar classes as MVVM Cross library.

Azure Mobile Services are now replaced by Microsoft.DataSync.Client.

And to compare:

Xamarin.Forms ERP .NET MAUI ERP


Telerik UI for Xamarin Telerik UI for .NET MAUI
MVVM cross MVVM community toolkit
Microsoft.Azure.Mobile.Client Microsoft.Datasync.Client
Microsoft.Azure.Mobile.Client.SqlLiteStore Microsoft.Datasync.Client

16 © 2023 Progress. All Rights Reserved.


Xamarin packages installed

.NET MAUI packages installed

17 © 2023 Progress. All Rights Reserved.


4. Move Independent Code
Next, I started to move all code that was “independent” from the technology stack like
Constant.cs, Layout.cs, EmbededResources.cs and Converters folder. Here, I recommend
building the new app to ensure that everything is OK.

Then I moved the Serialization folder with all classes. The interesting part here is the usage
of Colors API.

Login and Authentication


I decided to port the app function by function. I first ported the pages that did not rely on
data, such as Login and AboutPage, then moved on to the rest. To do that, I created at the
root level the same folders from the original app:
• Pages
• Services
• Models
• ViewModels
• Themes

18 © 2023 Progress. All Rights Reserved.


5. Pages and Themes, or the XAML
Part
I copied

LoginPage.xaml, LoginPage.xaml.cs, AboutPage.xaml.cs and AboutPage.


cs

and all xaml from the themes folders from the original app to my new app.

Base Classes and Data Context


The first things to update are the base classes and data context. In the original app,
we used MVVMcross and inherited MvxContentPage<ViewModels.
LoginPageViewModel>, which also took care of the data context of the page.

Now we will inherit from a simple ContentPage and set the BindingContext
in the constructor:

Replacing Telerik UI
When we used Progress Telerik UI for Xamarin, we used to use separate NuGets and
different namespaces for every respective assembly.

Now we are going to use one package and the telerik scheme, which is way more
convenient. This way, we do not have to remember what component belongs to which
assembly.

19 © 2023 Progress. All Rights Reserved.


So, replace all in xaml:

clr-namespace:Telerik.XamarinForms.*;assembly=Telerik.XamarinForms.*

with:

http://schemas.telerik.com/2022/xaml/maui

We will do a similar replacement in code-behind. Replace using Telerik.


XamarinForms.* with using Telerik.Maui.Controls;.

Note: Time to have a look into MAUIProgram.cs. To use Telerik, there


is a method to be added here called UseTelerik(). You can read
more about this and look into the specific migration hints per component in the Telerik
documentation Migrating from Telerik UI for Xamarin to .NET MAUI - Telerik UI for .NET
MAUI.

6. Consider the Images


In the original app, we have an Assets folder with images set as
EmbeddedResources loaded in a class like this:

public static ImageSource LoginBackgroundImage => ImageSource.


FromResource(“MauiErp.Assets.bg_login.png”,typeof(EmbeddedImages).
GetTypeInfo().Assembly);
C#

This approach is still working in .NET MAUI so we can move it directly. However, we can
benefit from the new resources mechanism. To do that, we can move the images under the
shared Resources/Images folder, which now every .NET MAUI project has. This will
automatically set the build action of the image to MauiImage, and we can shorten the code
to:

public static ImageSource LoginBackgroundImage => ImageSource.


FromResource(“ MauiErp.Assets.bg_login.png”) ;
C#

20 © 2023 Progress. All Rights Reserved.


You can learn more about working with images in .NET MAUI in the official Microsoft
documentation: Image - .NET MAUI | Microsoft Learn.

7. ViewModels
The ViewModels in the original app inherits from MvxViewModel class of the
MVVM cross library, which now we don’t have access to. That is why we are going to
replace it with ObservableObject using the MVVM community toolkit.

We will also replace IMvxCommand with ICommand.

For reference:

MVVMCross MVVM Community toolkit


MvxViewModel ObservableObject
IMvxCommandl ICommand

21 © 2023 Progress. All Rights Reserved.


8. AuthenticationService and
NavigationService
Great news for the AuthenticationService—no changes needed. We should just copy
AuthenticationService.cs, IAuthenticationService.cs as it is
to the Services folder of our new app.

As for the NavigationService, we have more things to do. The Xamarin.Forms app uses
MVVM cross navigation service, TabbedPage and NavigationPages.

Now, .NET MAUI has more capabilities to this without third-party services and we will use
the built-in features of the framework. Shell is also the recommended approach for .NET
MAUI apps and so we will replace that too using Shell Tabs. Then we will build our own
simple NavigationService to work with Shell.

public interface INavigationService


{
Task InitializeAsync();
Task NavigateToAsync(string route, IDictionary<string, object>
routeParameters = null);
Task PopAsync();
}

C#
public class NavigationService:INavigationService
{
public NavigationService() { }

public Task InitializeAsync()


{
return NavigateToAsync(“//LoginPage”);

}
public Task NavigateToAsync(string route, IDictionary<string,
object> routeParameters =
null)
{
return
routeParameters != null
? Shell.Current.GoToAsync(route, routeParameters)
: Shell.Current.GoToAsync(route);
}

public Task PopAsync()


{
throw new NotImplementedException();
}
}

C#

22 © 2023 Progress. All Rights Reserved.


And call it when needed like this. In our case, this code is needed in LoginpageViewModel:

await
this.navigationService.NavigateToAsync(“//AboutPage”);

C#

Note that to navigate between pages, we need to register them as route in XAML or in
code behind like this:

<TabBar>
<ShellContent Title=”Login” Route=”LoginPage”
ContentTemplate=”{DataTemplate pages:LoginPage}”
/>
<ShellContent Title=”About” Icon=”About.png”
ContentTemplate=”{DataTemplate pages:AboutPage}”
Route=”AboutPage”/>
</TabBar>
XML

Register the Services

While we relied on MVVM cross in the Xamarin.Forms version of the app, it is now time to
do this ourselves. .NET MAUI allows us to do it easily with the built-in dependency
injection, so I am just adding the following code to MAUIprogram.cs:

builder.Services.AddSingleton<IAuthenticationService,
AuthenticationService>();
builder.Services.AddSingleton<INavigationService,
NavigationService>();

C#

23 © 2023 Progress. All Rights Reserved.


Then, I create a static Services provider in the AppShell.cs that I can use later in the view
models to access the services:

App.cs

public partial class App : Application


{
public static IServiceProvider Services;

public App(IServiceProvider provider)


{
InitializeComponent();
Services = provider;
MainPage = new AppShell(Services.GetService<INavigationServi
ce>());
}
}

C#
LoginPageViewModel.cs (how to access the services):
this.authService = App.Services.GetService<IAuthenticationServi
ce>();

C#

If you made all changes to both pages and their respective viewmodels, now we can build
our app and test it. It will look like this:

9. Migrating Datamodels and Services


Now it is time to do some heavy lifting and move the data classes and the related classes
consuming our ERP services—updating Microsoft.WindowsAzure to Microsoft.Datasync. To
do that, we copy all Pages, Models, ViewModels and Services classes.

24 © 2023 Progress. All Rights Reserved.


Similar to migrating the LoginPage and AboutPage, we need to replace all changes
described above in the rest of the xaml pages and view models.

And then we are focusing on moving the ErpService and using DataSync.

Replace namespace:

using Microsoft.WindowsAzure.MobileServices; using Microsoft.


WindowsAzure.MobileServices.SQLiteStore; using Microsoft.
WindowsAzure.MobileServices.Sync;

C#

With:

Microsoft.Datasync.Client
Microsoft.Datasync.Client.SQLiteStore

C#

Here are the two APIs that will help you do the replacement. In my opinion, a better
approach here is to consider and write the service from scratch following the Microsoft
documentation.

Note: If your web service application is several years old, it is best to consider updating it
first as it may not be compatible with using DataSync client. Again, refer to MS docs here
and here for more details.

And here are some comparisons.

Xamarin .NET MAUI

IMobileServiceSyncTable<Vendor> IRemoteTable<Vendor>

const string offlineDbPath =


const string offlineDbPath =
FileSystem.CacheDirectory + “/
@”localstore.db”;
offline.db”

DeleteAsync DeleteItemAsync

InsertAsync InsertItemAsync

UpdateAsync ReplaceItemAsync

ToEnumerableAsync ToAsyncEnumerable

25 © 2023 Progress. All Rights Reserved.


Xamarin

this.client = new MobileServiceClient(Constants.ApplicationURL);


var store = new MobileServiceSQLiteStore(offlineDbPath);
store.DefineTable<Vendor>();
store.DefineTable<Product>();
store.DefineTable<Order>();
store.DefineTable<Customer>();

this.client.SyncContext.InitializeAsync(store, new
ErpMobileServiceSyncHandler());

//this.CurrentClient.
this.vendorTable = client.GetSyncTable<Vendor>();

C#

.NET MAUI

var store = new Microsoft.Datasync.Client.SQLiteStore.


OfflineSQLiteStore(new Uri(offlineDbPath).AbsoluteUri);
var options = new DatasyncClientOptions
{
OfflineStore = store
};
// Initialize the client.
client = new DatasyncClient(Constants.ApplicationURL, options);
this.client.InitializeOfflineStoreAsync();
C#

Xamarin

this.client = new MobileServiceClient(Constants.ApplicationURL);


C#

.NET MAUI

this.client = new MobileServiceClient(Constants.ApplicationURL);


C#

And again, register the services in MauiProgram.cs:

builder.Services.AddSingleton<IErpService, ErpService>();
C#

26 © 2023 Progress. All Rights Reserved.


In the result we now receive, you can see some minor differences:

Xamarin vs. .NET MAUI

10. Custom Renderers


Our app contains a simple custom renderer in Android that we don’t need any more as
we transformed TabbedPage to Shell Tabs. However, our next chapter will be focused on
renderers and how to deal with them.

11. MauiSplash Screen & Icon


In Xamarin.Forms, we had different resources and splash screen configurations, but now
we can use one shared Resource folder and use the new type as MauiSplashScreen
to update them.

Still, here we need help from a friend—our UX designer to give us .svg files instead of
.png.

Note also that if you run the app on Windows, the splash screen will not appear. Do not
search for an error, it is simply not supported for now in WinUI.

27 © 2023 Progress. All Rights Reserved.


Conclusion
.NET MAUI offers all we need to port our app to the next level, and there are also enough
resources now that can support you in this effort.

The time needed for such a migration is not a constant, as it depends on many factors, but
I hope this guide will help you plan the major parts.

Again, here they are for our app: replacing the MVVM API, changing the Navigation API,
rewriting the connection with Azure services, and the easiest transition—replacing Telerik
UI for Xamarin with Telerik UI for .NET MAUI.

Part 4: How to Migrate


Xamarin.Forms Renderers
to .NET MAUI Handlers?
Should We?
When it comes to custom renderers in your Xamarin.Forms app, one option to migrate
them to .NET MAUI is handlers.

After having ported our Xamarin project to .NET MAUI, we now need to sort out the topic
of platform customization.

In Xamarin.Forms, one of the main tools available to you is custom renderers. So how do
you achieve the same functionality in .NET MAUI? Let’s see:
• What are the options?
• Which one to choose?
• Details for both options

28 © 2023 Progress. All Rights Reserved.


What Are the Options?
Currently, we can either:

• Option 1: Move the code – transfer our old code with some modifications but using
the same renderers

• Option 2: Rewrite renderers to handlers – use the new API and architecture that
.NET MAUI offers us, handlers and mappers

So, How to Choose?


The first approach is faster when we are talking about dev time, so choose this as an entry
point if you want quick results or if you still have not used handlers.

Bear in mind that keeping renderers is not a good solution in the long term as the new
approach is there for a purpose. Handlers and mappers are the result of the new and
better architecture of .NET MAUI, which brings us performance improvements and easy
support for new platforms.

However, one important thing to consider also—not all Microsoft custom renderers are
ported to the new technology as a Cell or ListView. In this case, if you use them, you
simply do not have a choice—your custom renderer must stay for now. However, such
components are rarer and rarer—check them out in the Microsoft article here.

Now, let’s review both options in detail.

Option 1: Continue to Use the Same


Renderers
With some modification, the custom renderers from your Xamarin app can be reused and
are still supported in .NET MAUI. However, note that this will not be the case in the long
term, so this is a short-term solution, and the recommended way is to scroll to the second
option.

29 © 2023 Progress. All Rights Reserved.


Still, here are the main steps to add the custom renderers from your Xamarin project to
.NET MAUI. It is important to know that you can still use your renderers almost without
change. To do that, you need to:

1. Move the Files to the Right Place


Every new .NET MAUI project has a Platforms folder with a subfolder for the respective
platforms. Move your renderers there.

For example, if we want to customize the entry control, we will have the same custom
MyEntry.cs class to inherit the Entry and custom renderer for every affected platform:

Xamarin.Forms vs. .NET MAUI files

2. Modify the Code a Little Bit

If you still haven’t changed the namespaces, now is the time.

Any reference to Xamarin.Forms.* namespaces needs to be removed, and then you can
resolve the related types to Microsoft.Maui.*.

30 © 2023 Progress. All Rights Reserved.


You should also remove any ExportRenderer attributes as they won’t be needed in .NET
MAUI. For example, the following should be removed for a UWP-specific renderer:

[assembly: ExportRenderer(typeof(MyEntry),
typeof(XamarinRendererProject.UWP.MyEntryRenderer))]

namespace XamarinRendererProject.UWP

C#

3. Register the Renderers


Open MauiProgram.cs.

Add a using statement for the Microsoft.Maui.Controls.Compatibility.Hosting


namespace.

Call UseMauiCompatibility on the MauiAppBuilder object in the CreateMauiApp method,


and configure each renderer using conditional compilation per platform:

using Microsoft.Maui.Controls.Compatibility.Hosting;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder .UseMauiApp<App>()
.UseMauiCompatibility()
.ConfigureFonts(fonts => { fonts.AddFont(“OpenSans-Regular.
ttf”, “OpenSansRegular”); fonts.AddFont(“OpenSans-Semibold.ttf”,
“OpenSansSemibold”); })
.ConfigureMauiHandlers((handlers) => {
#if Windows handlers.AddHandler(typeof(MyEntry),
typeof(MyMauiProject.Windows.Renderers. MyEntryRenderer));

#elif IOS......
#endif
});
return builder.Build();
}
}

C#

31 © 2023 Progress. All Rights Reserved.


So, it is working. Then why are we talking about migration? Renderers are one of the
architectural changes that bring us performance improvement in .NET MAUI compared to
Xamarin.Form. Also, although renderers are currently supported, Microsoft does not claim
that this will be true in the upcoming version of .NET.

Option 2: Using Handlers and


Mappers
This new handler concept is one of the key aspects of evolving Xamarin to .NET MAUI and
in the improved performers and ability to support more platforms.

What Are These Handlers?


The handlers are already implemented classes in .NET MAUI that match every type of
control/view that exists in .NET MAUI via an interface.

Note that their scope is global. This means that if we use and modify one handler for a
control—let’s say Button—this customization will affect all buttons.

.NET MAUI handlers are accessed through their control-specific interface, such as IButton
for a Button. This avoids the c ross-platform control having to reference its handler, and
the handler having to reference the cross-platform control. Clean architecture, right?

Some important properties that we need to know to understand the concept:

• PlatformView – Each handler class exposes the native view for the cross-platform
control via its PlatformView property. This property can be accessed to set native view
properties, invoke native view methods and subscribe to native view events.

• VirtualView – The cross-platform control implemented by the handler is exposed via


its VirtualView property.

What Are Mappers?


Handlers can be used and accessed, but when we want to modify how a specific property
or behavior is to be changed, we actually use mappers.

32 © 2023 Progress. All Rights Reserved.


There are two types of mappers:

• A property mapper defines what Actions to take when a property change occurs
in the cross-platform control. It’s a Dictionary that maps the cross-platform control’s
properties to their associated Actions. Each platform handler then provides
implementations of the Actions, which manipulate the native view API. This ensures
that when a property is set on a cross-platform control, the underlying native view is
updated as required.

• A command mapper defines what Actions to take when the cross-platform control
sends commands to native views.

So, handlers and mappers are great, but how do we use them? For example, how can we
port our code and modify the color of Entry component? Here are three ways.

Scenario 1: Access the Handler When You Need to Modify It

This approach is not very difficult, and it is just one of the major scenarios to use handlers.
To use this approach, simply add the “Handler” keyword to the component you need to
modify (for example, in the constructor of our content page) and you will be good to use it.

When you want to customize the entry, you will need EntryHandler—for a button,
ButtonHandler, etc.

Ex: Microsoft.Maui.Handlers.EntryHandler

Then set the right mapping and use the PlatformView to access the native control.
(MyCustomization is a sample key name that we put in our mapping.)

void ModifyEntry()
{
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(“**MyCus
tomization**”, (handler, view) =>
{
#if WINDOWS
if (view is MyEntry) //here we check
and customize only MyEntry instances and not all entries, without
this we can easily customize all entries if we needed it
{
handler.
PlatformView.Background = Brush.Cyan;
}
#endif
});
}

C#

33 © 2023 Progress. All Rights Reserved.


Scenario 2: Use Handler Lifecycle Events to Access It and
Modify Properties of the Components

Handlers have their lifecycles and set of events that we can listen to. For example, we can
subscribe to the Entry instance and listen for HandlerChanged and HandlerChanging and
change the properties that we need there.

A complete example can be found in Microsoft docs .NET MAUI control customization with
handlers - .NET MAUI | Microsoft Learn and in Telerik docs showing this approach with
RadListView.

Scenario 3: Create a Custom Component and a New Handler

The process for this approach is based on six steps:


1. Create an interface, implementing IView.
2. Create a subclass of the ViewHandler.
3. In the ViewHandler subclass, override the CreatePlatformView method that renders
the platform control.
4. Create the PropertyMapper dictionary, which handles what actions to take when
property changes occur.
5. Create a custom control by subclassing the View class and implementing the control
interface.
6. Register the handler using the AddHandler method in the MauiProgram class.

For the full detailed example—please go to the MS docs here.

Conclusion

Handlers are so flexible, they bring performance improvements and their API is more
extensible. It needs time to get used to the concept, but it is worth it and is one of the
major reasons that make .NET MAUI better than Xamarin.Forms. So, go ahead and play
with this. You can also consider reading these Telerik and Microsoft resources for more
scenarios.

34 © 2023 Progress. All Rights Reserved.


Part 5: Practical Tips for
Migrating from Xamarin to
.NET MAUI
Tip for Starting: Use Upgrade
Assistant and a Blank New Project
You can make the first step to your migration by using the Upgrade Assistant VS
extension as part of VS 2022 or install it separately with cmd. My suggestion is to use it
from the cmd, as there you have more visibility over what happens. The extension also
does not create a backup folder, so have this in mind and back up your project manually.

Another nice trick is to use the --non-interactive parameter of the Upgrade


Assistant as this saves you time from manually choosing the next step.

The assistant will help by doing these steps for you:


• Update your project file to be SDK-style
• Update Microsoft namespaces
• Address some API changes

After that, you will still have to implement a good number of manual changes, such as
updating any third-party libraries and API changes.

35 © 2023 Progress. All Rights Reserved.


Some advice I can offer is to use the converted files but to add them manually piece by
piece to a newly created blank .NET MAUI app. This will give you a nice shell navigation
and a clean, ready-to-build project to start with.

Tip for Namespaces: Use XAML


Schemes When Possible
All Xamarin.Forms namespaces are now renamed to match the appropriate MAUI naming.
So you can do a mass replace from Xamarin.Forms* to Microsoft.MAUI* or just use the
XAML scheme.

Change http://xamarin.com/schemas/2014/forms to http://schemas.microsoft.com/


dotnet/2021/maui

This is also true when replacing Telerik UI for Xamarin with Telerik UI for .NET MAUI.
Do a mass replace from Telerik.XamarinForms.* to Telerik.MAUI.Controls or just use the
XAML scheme: xmlns:telerik=”http://schemas.telerik.com/2022/xaml/maui.

For more changes in the Telerik API, you can follow the articles below for Xamarin-to-MAUI
migration guides for Telerik UI controls:
• Common migration
• Accordion
• AutoComplete
• CheckBox
• ComboBox
• DataForm
• DatePicker
• DateTimePicker
• Entry
• ImageEditor
• ListPicker
• ListView
• MaskedEntry
• ProgressBar
• SignaturePad
• TemplatedPicker
• TimePicker
• TimeSpanPicker

36 © 2023 Progress. All Rights Reserved.


Tip for Azure Mobile Services
If your mobile app already uses Azure, an important note is that Microsoft.WindowsAzure.
MobileServices are now rebranded as Microsoft Datasync.Client.

Microsoft.Azure.Mobile.Client Microsoft.Datasync.Client

Microsoft.Azure.Mobile.Client.SqlLiteStore Microsoft.Datasync.Client.SQLLiteStor

There are also a lot of API changes, so be sure to read the MS docs before using them.

Tip for Checking the Device: Use the


New DeviceInfo and DevicePlatform
Classes
Xamarin.Forms has a Xamarin.Forms.Device class that helps you interact with the device
and platform the app is running on. .NET MAUI has several classes to be used instead and
not just one to replace it. The most important are Microsoft.Maui.Devices.DeviceInfo.Idiom
and DevicePlatform.

Refer to this MS doc for the detailed use cases: Device information - .NET MAUI | Microsoft
Learn.

A Simple Example of Replacing the Code


Xamarin.Forms code:

if (Device.Idiom == TargetIdiom.Phone)
{

C#

37 © 2023 Progress. All Rights Reserved.


.NET MAUI code:

if (DeviceInfo.Idiom == DeviceIdiom.Phone)
{

C#

Tip If Using Microsoft ListView:


Replace ListView with CollectionView
.NET MAUI is coming with a better architecture successfully implemented in more of the
existing Xamarin components. However, it is completely understandable that not all of the
old code can inherit the new changes.

That is why although .NET MAUI ListView has a lot of features and it is completely
possible to use it in the same way as in Xamarin, it is recommended to consider its
replacement with CollectionView.

Tip for Colors: With Two New Classes,


CommunityToolkit.Maui Is Here to
Help
In Xamarin.Forms, the Xamarin.Forms.Color is a struct and 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. So to find the AliceBlue in MAUI, you
can use the Colors class which defines 148 public static read-only fields for common colors.

Note also that Xamarin.Forms.Color.Default has no .NET MAUI equivalent. Microsoft.Maui.


Graphics.Color objects default to null.

38 © 2023 Progress. All Rights Reserved.


When you convert colors, a nice tool to look at is CommunityToolkit.Maui and the
converters that convert colors to and from hex, RBG, etc.

Read more: Converters - .NET MAUI Community Toolkit - .NET Community Toolkit |
Microsoft Learn.

Layout Behavior Changes from


Xamarin.Forms
The new architecture of .NET MAUI brings changes in the layout, too. Some that are worth
looking into are the following:

Layout Xamarin.Forms .NET MAUI Recommendation

Grid Columns and rows Columns and rows Add ColumnDefinitions and RowDefinitions.
can be inferred must be explicitly
from XAML. declared.
RelativeLayout Requires the Use Grid instead or add the xmlns for the
compatibility compatibility namespace.
namespace.

StackLayout Children can hildren are stacked If you need child views to fill space, change to
fill space in the and will go beyond a Grid. You can also use VerticalStackLayout
stacking direction. available space. andHorizontalStackLayot instead.

These are just the major changes that you will face when migrating your Xamarin.Forms
app to .NET MAUI—but remember, rewriting and improving code cannot come without
such changes, and they are a result of new and better functionality that .NET MAUI brings
to the table.

Is .NET MAUI Always the Answer?


Now that we’ve discussed the performance and architectural benefits of migrating your
app to .NET MAUI, hopefully, you know what to do with your Xamarin apps. But what if you
have other apps built with older generations of .NET technology that you might want to
migrate to the future—let’s say a WPF app? Is .NET MAUI also the way to go?

39 © 2023 Progress. All Rights Reserved.


In the vast ocean of Windows-based applications and programming languages, this guide
wouldn’t be complete if I didn’t give due credit to another .NET technology that also
bears the potential of cross-platform—Blazor Hybrid. In the next chapter, let’s compare a
migration of a WPF app to both .NET MAUI and Blazor Hybrid.

Part 6: .NET MAUI vs Blazor


Hybrid
Your .NET apps can gain so many advantages if you make them cross-platform, but what’s
the best way to do that—with .NET MAUI or Blazor Hybrid?

Let’s say you have a great WPF app, perhaps your main target users are those using
Windows OS. However, the usage of Android, iOS and macOS devices continues to
increase and they are now a very important part of our ecosystem.

For reference, we can take a look at the data in Wikipedia: Usage share of operating
systems - Wikipedia.

Until recently, to reach all these users was not easy—you would write four different apps
if you needed to rely on a native look and feel for the user experience or to choose the
web stack and access the users via browsers. Let’s be honest, all of these options required
learning different technologies and going outside the .NET world.

But now, the .NET family is so big, and we can use it to extend and modernize our desktop
application to reach the sky (or, in other words, Linux, iOS, macOS and Android).

How? Let’s take a look at the most modern children in the family—.NET MAUI and .NET
Blazor. Both are a great choice to consider when thinking how to bring our desktop app to
new territories, but which one is right for you? Let’s take a quick test!

40 © 2023 Progress. All Rights Reserved.


Which One to Use?
Please take this simple test and choose the technology stack for your needs:

Is the native No, I want my UI to look Do you love XAML? No, I prefer CSS +HTML
look & feel important? the same everywhere

Yes, I want my UI to I love XAML and I’ll try


look native to reuse some of my UI

.NET Do you have all needed UI


Hybrid
components?
MAUI Blazor

Yes, I use Telerik UI for No, need Blazor


.NET MAUI to fill ScheduleView or other
the missing UI

So, if the result led you to using .NET MAUI, scroll to the next heading. If the results led
you to using a Blazor Hybrid app, this is a great option too and we will look into it further
down this chapter.

Transform a WPF App to Cross-


Platform with .NET MAUI

.NET MAUI XAML vs. WPF XAML


.NET MAUI is a cross-platform XAML-based technology, so if you have strong WPF
experience, you will have a quick learning curve—still, prepare to meet some differences.

XAML is a great invention and I personally like it a lot. However, there is no XAML
standard, which makes things complicated when we are talking about unification and
migration.

With .NET MAUI, we can leverage our XAML and C# skillset and bring our Windows
desktop app to more devices by moving it piece by piece.

41 © 2023 Progress. All Rights Reserved.


.NET MAUI XAML is actually the 2009 XAML Specification, the same as another member
of the .NET family—WinUI. If you are already familiar with WinUI, you are familiar with a
big part of MAUI XAML. However, if your experience is with Silverlight/WPF XAML, which
follows the 2006 XAML Specification, you will see some differences. I listed below the most
interesting to start with:

Using Text

Here the well-known Label still exists, but not the TextBox component. In .NET MAUI, we
use Entry for short text and the Editor component for multiple lines. Telerik RadEntry is
also a great component when we are talking about text with some features that you may
need, such as built-in Validation.

Foreground is also replaced with the TextColor property.

Using Borders

In WPF, we have built-in properties of the FrameworkElement objects Buttons, Labels,


TextBox, etc. to use the BorderThickness, CornerRadius. In .NET MAUI, we have to use a
container control that draws a border, background or both around another control. Here
we can use the .NET MAUI Border component, where we need to use its StokeShape
property to define the shape and corner radius or the Telerik Border component
that exposes directly the well-known properties for a WPF dev—CornerRadius and
BorderThickness.

Height/Width vs. RequestHeight/RequestWidth

In WPF, we can rely on the Height and Width properties of the FrameWorkElement
class, while in .NET MAUI the framework offers us HeightRequest and WidthRequest
instead, which are properties of the VisualElement class. These properties will call the
GetSizeRequest, which will in turn modify the final size the element receives during a
layout cycle.

42 © 2023 Progress. All Rights Reserved.


Layouts

The base layouts in .NET MAUI are also different from WPF, and I suggest you take a look
at the .NET MAUI documentation before porting the code directly: Layouts - .NET MAUI |
Microsoft Learn.

Note that every .NET Multi-platform App UI control that derives from View (this includes
views and layouts) has HorizontalOptions and VerticalOptions properties, of type
LayoutOptions, and these are your new best friends when positioning the elements.

For example, use it to position a Label inside a StackPanel:

<HorizontalStackLayout HorizontalOptions=”Center”
Margin=”0, 20, 0, 20”>
<Label Text=”Searching... “
FontSize=”16”
TextColor=”#8E8E93”/>
</HorizontalStackLayout/>

XML

I am listing here the common alternatives to the most used layouts from WPF:

WPF .NET MAUI

Canvas X

Telerik DockLayout: .NET MAUI DockLayout


DockPanel Documentation - Overview - Telerik UI for
.NET MAUI

Grid Grid – some properties are different

StackPanel, VerticalStackPanel,
StackPanel HorizontalStackPanel

VirtualizingPanel X – not a direct alternative for now

FlexLayout/ Telerik WrapLayout: .NET


MAUI WrapLayout Documentation -
WrapPanel RadWrapLayout Overview - Telerik UI for
.NET MAUI

The ScrollViewer component is also not available, but you can rely on ScrollView to achieve
scrolling functionality. Read more about its API in the documentation: ScrollView - .NET
MAUI | Microsoft Learn.

43 © 2023 Progress. All Rights Reserved.


Using Windows

.NET MAUI is a successor of the mobile Xamarin framework where windows are not
very used. That is why, by default, the base class of the XAML pages is not Window, but
ContentPage. ContentPages are used to achieve the navigation in a .NET MAUI app,
so the root window of the app uses them to change its content. When you migrate WPF
pages, change the base class to ContentPage.

Also, there are some “tricky” moments when we want to manipulate the window. For
example, to change its size. Here is a simple code sample for how to do that in App.xaml:

public partial class App : Application


{
const int WindowWidth = 450;
const int WindowHeight = 800;

public App()
{
InitializeComponent();

Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMappin
g(nameof(IWindow), (handler, view) =>
{
#if WINDOWS
handler.PlatformView.Activate();

IntPtr windowHandle = WinRT.Interop.WindowNative.


GetWindowHandle(handler.PlatformView);
AppWindow appWindow = AppWindow.
GetFromWindowId(Win32Interop.GetWindowIdFromWindow(windowHandle));

appWindow.Resize(new SizeInt32(WindowWidth,
WindowHeight));
#endif
});
MainPage = new AppShell();
}
}

C#

44 © 2023 Progress. All Rights Reserved.


Another way is to override the App’s CreateWindow method, but only with versions .NET 7
and above.

      protected override Window CreateWindow(IActivationState


activationState)
{
       var window = base.CreateWindow(activationState);
       window.MinimumHeight = 600; // set minimal window height
       window.MinimumWidth = 800; // set minimal window width
       return window;
      }

C#

With .NET 7, we can use multiple windows. This can be achieved by creating a Window
object and opening it using the OpenWindow method on the Application object.

Window secondWindow = new Window(new MyPage());


Application.Current.OpenWindow(secondWindow);

C#

Note that multi-window support works on Android and Windows without additional
configuration. However, additional configuration is required on iPadOS and Mac Catalyst.
Read more about how to set it up in the Microsoft documentation here: .NET MAUI
windows - .NET MAUI | Microsoft Learn.

Events

The naming convention for events is also a little bit different. But basically adding “ed” to
the existing WPF events should do the trick.

Example: Button.Click is now Button.Clicked.

Another interesting thing to point out is the key events. They are not exposed directly.
However, most of the UI components have their events that fire when the focus is lost or
the text is changed, and you can subscribe to them to do your job.

45 © 2023 Progress. All Rights Reserved.


For example, you can subscribe to Completed event, which is fired when Enter is read into
the Entry:

MyEntry.Completed += MyEntry_Completed;

private void MyEntry_Completed(object sender, EventArgs e)


{
/// your code here
}

C#

Another way is to access the native windows component and attach the event.

To do that, you can obtain the UIElement on which the key-press events should be
detected from Handler.PlatformView. And then you can hook up the native events.

var handler = mauiView.Handler;

UIElement? nativeView = handler?.PlatformView as UIElement;


if (nativeView != null)
{
nativeView.KeyDown += this.PlatformView_KeyDown;
nativeView.KeyUp += this.PlatformView_KeyUp;
nativeView.PreviewKeyDown += this.PlatformView_PreviewKeyDown;
}

C#

Images & Resources

This is one of the great features of .NET MAUI—a common shared folder where you can
put the images, use the MAUIImage build action and directly access them in the code
without worrying about where exactly they are.

For example, if you place add.png to the image folder, you can access it from a button by
its short name:

46 © 2023 Progress. All Rights Reserved.


Customization

Another important thing that you should know is how to customize UI or behavior per
platform. You can use two major approaches:

1. Write platform-specific code and use the #if directives in C#:

#if ANDROID using Android.Content;


using Android.Views;
using Android.Runtime;
#elif IOS using UIKit;
#endif

C#

For more information, see .NET MAUI invoking platform code - .NET MAUI | Microsoft
Learn.

Or the OnPlatform property in XAML:

<ContentPage xmlns=”http://schemas.microsoft.com/dotnet/2021/
maui” xmlns:x=”http://schemas.microsoft.com/winfx/2009/xaml”
x:Class=”...”>
<ContentPage.Padding>
<OnPlatform x:TypeArguments=”Thickness”>
<On Platform=”iOS, Android” Value=”10, 20, 20, 10” />
</OnPlatform>
</ContentPage.Padding>
</ContentPage>

XML

For more information, see OnPlatform Markup Extension.

2. Use the new mechanism in .NET MAUI—handlers.

Accessibility

Another very important topic for modern apps is accessibility. In WPF, we have a lot of tools to achieve
that. One of them is the AutomationPeer class. In .NET MAUI, we will use semantic properties to make
our app accessible. Read more about semantic properties here: Build accessible apps with semantic
properties - .NET MAUI | Microsoft Learn.

47 © 2023 Progress. All Rights Reserved.


Migration of a WPF application is not a trivial task, but it is worth it as .NET MAUI gives us
a lot of possibilities and supported platforms.

Now, let’s look at Hybrid Blazor.

What to Know When


Porting a WPF App to
Blazor Hybrid
If your result for this little quiz leads you to Blazor Hybrid, this is the part for you!

What situations might that be?

• The first case for using such an approach is if we want our app to have a unified UI,
to write the code at once but we need all desktop features, like file access system,
camera settings, etc.

• Another situation is when we have already ported our code to .NET MAUI but need
a component that the Blazor ecosystem has to offer, such as Telerik Pivot or Telerik
ScheduleView, for example, or another of the powerful components from Telerik UI for
Blazor.

Scenario 1
Unified UI

The best choice here is to create a new Hybrid Blazor app using Microsoft VS
Templates.

With .NET 7, you can choose between WPF Hybrid Blazor or .NET MAUI Blazor, and which
one to choose depends which OS you need to target.

48 © 2023 Progress. All Rights Reserved.


In this series, we are focused on the cross-platform experience, so .NET MAUI Hybrid
Blazor app is our choice.

Visual Studio directly creates a Blazor app wrapped in the .NET MAUI project structure.

Scenario 2
We have a great MAUI/WPF app but we need a component that only the Blazor
ecosystem has to offer.

For example, if you need to use Scheduling functionality in .NET MAUI, then you can look
into the rich Telerik UI for Blazor suite.

In this case, our .NET MAUI app is already created and we need to follow the steps below
to add the Blazor part or you can again create a blank MAUI Hybrid app and copy the
needed files from there.

1. Add the Razor SDK, Microsoft.NET.Sdk.Razor to your project by editing its first line
of the CSPROJ project file:

<Project Sdk=”Microsoft.NET.Sdk.Razor”>
Razor C#

2. Add the root Razor component for the app to the project Main.razor page:

A razor component is a page containing the UI for your needs. It is the place to write your
code when working with Blazor.

49 © 2023 Progress. All Rights Reserved.


3. Add your Razor components to project folders named Pages and Shared.

For example, the code that I will use to add the Scheduler is placed in the Pages folder:

@Page “/”
@Using Telerik.Blazor.Components.Scheduler.Models;
<Telerikscheduler Data=”@Appointments” @Bind-Date=”@Startdate”
Height=”600px” @Bind-View=”@Currview”

Allowcreate=”True” Allowdelete=”True”
Allowupdate=”True”
Confirmdelete=”True”

>
<Schedulerviews>
<Schedulerdayview Starttime=”@Daystart” Endtime=”@Dayend”
Workdaystart=”@Workdaystart” Workdayend=”@Workdayend” />
<Schedulerweekview Starttime=”@Daystart” Endtime=”@Dayend”
Workdaystart=”@Workdaystart” Workdayend=”@Workdayend” />
<Schedulermultidayview Starttime=”@Daystart” Endtime=”@
Dayend” Workdaystart=”@Workdaystart” Workdayend=”@Workdayend”
Numberofdays=”10” />
<Schedulermonthview></Schedulermonthview>
<Schedulertimelineview Starttime=”@Daystart” Endtime=”@
Dayend” Workdaystart=”@Workdaystart” Workdayend=”@Workdayend” />
</Schedulerviews>
</Telerikscheduler>

@code {
IEnumerable<Appointment> Appointments = new
List<Appointment>();
public DateTime StartDate { get; set; } = new DateTime(2021, 6,
21);
public SchedulerView CurrView { get; set; } = SchedulerView.
Week;

//the time portions are important


public DateTime DayStart { get; set; } = new DateTime(2000, 1,
1, 8, 0, 0);
public DateTime DayEnd { get; set; } = new DateTime(2000, 1, 1,
20, 0, 0);
public DateTime WorkDayStart { get; set; } = new DateTime(2000,
1, 1, 9, 0, 0);
public DateTime WorkDayEnd { get; set; } = new DateTime(2000,
1, 1, 17, 0, 0);

protected override void OnInitialized()


{
LoadData();
}
private void LoadData()
{
Appointments = appointmentService.GetAppointments();
}
}

Razor C#

50 © 2023 Progress. All Rights Reserved.


4. Add your static web assets to a project folder named wwwroot (things like favicon,
fonts, etc.).

5. Add any optional _Imports.razor files to your project. This means list here the
additional libraries that you will use.

Here, to use Telerik UI for Blazor, the following code should be added:

@using Telerik.Blazor
@using Telerik.Blazor.Components
@using Telerik.FontIcons
@using Telerik.SvgIcons
<ContentPage xmlns=”http://schemas.microsoft.com/dotnet/2021/maui”
xmlns:x=”http://schemas.microsoft.com/winfx/2009/xaml”
xmlns:local=”clr-namespace:MyBlazorApp”
x:Class=”MyBlazorApp.MainPage”>

<BlazorWebView HostPage=”wwwroot/index.html”>
<BlazorWebView.RootComponents>
<RootComponent Selector=”#app” ComponentType=”{x:Type
local:Main}” />
</BlazorWebView.RootComponents>
</BlazorWebView>

</ContentPage>

Razor C#

6. Modify the CreateMauiApp method of your MauiProgram class to register the


BlazorWebView control for use in your app.

To do this, on the IServiceCollection object, call the AddMauiBlazorWebView method to


add component web view services to the services collection:

51 © 2023 Progress. All Rights Reserved.


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

builder.Services.AddMauiBlazorWebView();
#if DEBUG
builder.Services.AddMauiBlazorWebViewDeveloperTools();
#endif
// Register any app services on the IServiceCollection
object
// e.g. builder.Services.AddSingleton<WeatherForecastServi
ce>();

return builder.Build();
}
}

C#

And when the BlazorWebView is added and your .NET MAUI app becomes a .NET MAUI
Blazor Hybrid app, it is time to add Telerik ScheduleView. The steps to do that are:

7. Add Telerik libraries by following the link: Download Telerik UI for Blazor

8. Add the Telerik client assets by adding these two lines in the <head> tag of
wwroot/index.html:

<link rel=”stylesheet” href=”_content/Telerik.UI.for.Blazor/css/


kendo-theme-default/all.css” />
<script src=”_content/Telerik.UI.for.Blazor/js/telerik-blazor.js”
defer></script>

HTML

52 © 2023 Progress. All Rights Reserved.


9. Include @using statements in the _imports.razor file:

@using Telerik.Blazor
@using Telerik.Blazor.Components
@using Telerik.FontIcons
@using Telerik.SvgIcons

Razor C#

10. Add the TelerikRootComponent in Main.razor page:

<TelerikRootComponent>
<Router AppAssembly=”@typeof(Main).Assembly”>
<Found Context=”routeData”>
<RouteView RouteData=”@routeData” DefaultLayout=”@
typeof(MainLayout)” />
<FocusOnNavigate RouteData=”@routeData” Selector=”h1”
/>
</Found>
<NotFound>
<LayoutView Layout=”@typeof(MainLayout)”>
<p role=”alert”>Sorry, there’s nothing at this
address.</p>
</LayoutView>
</NotFound>
</Router>
</TelerikRootComponent>

Razor C#

11. Register the Telerik Services by modifying once the CreateMauiApp() method:

// register the Telerik services


builder.Services.AddTelerikBlazor();

Razor C#

53 © 2023 Progress. All Rights Reserved.


And then if you followed all of the steps above, you should be able to see Telerik UI as part
of your .NET MAUI project. The .NET MAUI project in my case contains also a .NET MAUI
ListView on the left, and the BlazorWebView on the right:

<?xml version=”1.0” encoding=”utf-8” ?>


<ContentPage xmlns=”http://schemas.microsoft.com/dotnet/2021/maui”
xmlns:x=”http://schemas.microsoft.com/winfx/2009/xaml”
xmlns:local=”clr-namespace:MauiHybridBlazor”
x:Class=”MauiHybridBlazor.MainPage”
BackgroundColor=”{DynamicResource
PageBackgroundColor}”>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=”10”/>
<RowDefinition Height=”*”/>
<RowDefinition Height=”Auto”/>

</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”300” />
<ColumnDefinition Width=”*” />
</Grid.ColumnDefinitions>
<ProgressBar
x:Name=”isRefreshingControl”
/>

<ListView
x:Name=”itemListControl”
Grid.Row=”1”
Margin=”10”
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<HorizontalStackLayout
HorizontalOptions=”Center” VerticalOptions=”Center” >
<CheckBox Margin=”1” Color=”Black”
/>
<Label Text=”{Binding}”
VerticalOptions=”Center”/>
</HorizontalStackLayout>
</ViewCell>

</DataTemplate>
</ListView.ItemTemplate>
</ListView>

…........
<BlazorWebView Grid.Column=”1” Grid.RowSpan=”3”
x:Name=”blazorWebView” HostPage=”wwwroot/index.html”>
<BlazorWebView.RootComponents>
<RootComponent Selector=”#app”
ComponentType=”{x:Type local:Main}” />
</BlazorWebView.RootComponents>
</BlazorWebView>
</Grid>
</ContentPage>

XML

54 © 2023 Progress. All Rights Reserved.


Conclusion
The .NET world is more powerful than ever and now you can choose between mobile,
web and desktop .NET frameworks and mix them to implement the best solution for your
users.

Migrating to .NET MAUI can improve your application development by providing


a modern, cross-platform framework that supports native UI controls and stellar
performance. This is the future, and you are lucky to make it happen. Thank you for your
time and stay tuned for more resources on the topic.

Telerik UI for .NET MAUI library delivers 60+ components that will
accelerate your cross-platform application development and help you
modernize legacy projects.

55 © 2023 Progress. All Rights Reserved.


About The Author
Rossitsa Fakalieva

Rossitsa Fakalieva was the leader of the Telerik engineering teams working with
XAML technologies—Telerik UI for WPF, Telerik UI for Xamarin and Telerik UI for
.NET MAUI—for over a decade. She’s now dedicated to empowering women to
success in IT through her organizations, Women Who Code – Sofia and Coding
with Rossi.

Learn More

About Progress Worldwide Headquarters


Dedicated to propelling business forward in a technology-driven world, Progress Progress Software Corporation
(NASDAQ: PRGS) helps businesses drive faster cycles of innovation, fuel momentum and 15 Wayside Rd, Suite 400, Burlington, MA01803, USA
accelerate their path to success. As the trusted provider of the best products to develop, deploy Tel: +1-800-477-6473
and manage high-impact applications, Progress enables customers to build the applications and
experiences they need, deploy where and how they want and manage it all safely and securely.
Hundreds of thousands of enterprises, including 1,700 software companies and 3.5 million developers, facebook.com/progresssw
depend on Progress to achieve their goals—with confidence. Learn more at www.progress.com twitter.com/progresssw
youtube.com/progresssw
2023 Progress Software Corporation and/or its subsidiaries or affiliates. All rights reserved. linkedin.com/company/progress-software
Rev 2023/07 RITM0209014 progress_sw_

You might also like