Categories
.NET MAUI Desktop Getting Started Mobile Visual Studio Xamarin

.NET MAUI – What’s New in Preview 8

Changes in .NET MAUI Preview 8 with Abstract and Host Builder pattern. Windows, via WinUI 3, now part and parcel of the Single project ecosystem.

In the previous article, we’ve seen how to install/update the prerequisites that are necessary to work with .NET MAUI Preview 8 application.

In this article, we’re going to see the changes that got newly introduced as part of this preview and what’s changed from the earlier ones.

The most important thing is now WinUI artifacts, targeting the Windows platform, are now part of the Single project, the original design goal of .NET MAUI. Yes, one single project for all 4 presently supported target platforms. WinUI works on top of WindowsAppSDK, rebranded from Project Reunion, 1.0 (experimental) version.

Windows Platform in .NET MAUI Single Project Ecosystem
Windows Platform in .NET MAUI Single Project Ecosystem

If you’re working on a new project in Preview 8, you need to uncomment this TargetFrameworks tag containing the Windows target definition in the Project file. Use Ctrl + K + U shortcut key to avoid any error.

WindowsAppSDK (aka Project Reunion) Reference for targeting Windows via WinUI 3
WindowsAppSDK (aka Project Reunion) Reference for targeting Windows via WinUI 3

The target SDK version for Android is pushed to API level 31 (Android 12.0 – codenamed S) and hence it requires OpenJDK 11.

Android Target SDK - API Level 31
Android Target SDK – API Level 31

Below is the screenshot of the project artifacts, the orange arrow indicates wherever it is impacted in Preview 8.

.NET MAUI Preview 8 Application Artifacts
.NET MAUI Preview 8 Application Artifacts

To work with this single project, use the dropdown to the left of the Play button and open the Framework sub-menu to switch to a different target platform, and then choose the appropriate device (physical/virtual) to run the application.

Switching Target Platform in .NET MAUI Single Project Ecosystem
Switching Target Platform in .NET MAUI Single Project Ecosystem

The execution of the application code will always start from the target platform and then, at some point, the control transfers to this cross-platform (shared) code. From there on, it is a neat abstraction down the line.

To know more about this, we need to look at how each of the platform works:

Let’s start with Android, execution starts from the MainApplication class that is marked with the [Application] attribute (in MainApplication.cs). This class inherits from the class titled MauiApplication, an abstract class with an abstract method named CreateMauiApp() returning an instance of type MauiApp. The definition for this abstract method is to be provided in this MainApplication class.

Android Application Startup
Android Application Startup

Next let’s look at iOS and Mac Catalyst, since both of them are from the Apple family, they follow a similar construct:

Execution starts from the Main() method (in Program.cs). In which, UIApplication.Main() method is invoked with a reference to AppDelegate type. Here, AppDelegate class inherits from the class titled MauiUIApplicationDelegate, again an abstract class with an abstract method named CreateMauiApp() returning an instance of type MauiApp. The definition for this abstract method is to be provided in this AppDelegate class.

iOS Application Startup
iOS Application Startup
Mac Catalyst App Startup
Mac Catalyst Application Startup

Finally, let’s look at the Windows platform, execution starts from the Main() method (in Program class), there invoking the Application.Start() method with the instance of the App class (see the definition of InitializeComponent() method in App.xaml.cs). This App class inherits from the class titled MauiWinUIApplication, again an abstract class with an abstract method named CreateMauiApp() returning an instance of type MauiApp. The definition for this abstract method is to be provided in this App class.

Windows Application Startup
Windows Application Startup

This certainly brings some fond memories of the initial days of my learning career with Microsoft Foundation Class (MFC), a precursor to Windows Forms. In which, to build an app, a class needs to be inherited from CWinApp, an abstract class with an abstract method titled InitInstance() that returns an instance of the type CWinApp in its definition. Near identical pattern.

Needless to say, all these platforms follow a similar pattern. Whenever there is a similarity, it can be moved to the shared code. Hence at this juncture, the execution transfers to the shared code.

This is where the proven Host Builder pattern starts to appear and is fully integrated into the App startup. As type MauiApp (a sealed class) is nothing but an implementation of IHost interface and is more versatile than the previous IStartup kind of implementation as it now includes Services, Configuration, Logging, and Lifetime.

App Startup - Host Builder Pattern
App Startup – Host Builder Pattern

In the shared code, a static method named CreateMauiApp() is defined (in MauiProgram.cs) that returns an instance of type MauiApp.

At first, CreateBuilder() method is called to initialize the Host (returns an object of type MauiAppBuilder).

Next, the shared App class is hooked into the Host Builder using the UseMauiApp<App>() generic method call (remember App class defines the MainPage and that’s the first UI to get rendered).

Then this is where all customizations are to be registered like Handlers, Compatibility Renderers, Effects, Essentials, Fonts, Lifecycle Events, Services, etc … To do so, invoke the appropriate Configure* extension methods. To define services, use the Services property on the builder object. Can be further simplified by writing extension methods, if necessary.

And then, the Build() method is to be invoked on the builder object and the return type is MauiApp.

Finally, this method, MauiProgram.CreateMauiApp(), is invoked in all the platforms for the must-define abstract method.

And there is a commonality in all the platform-specific base types by defining the below properties:

  1. Current
    • A read-only static property of the containing type (like Application.Current in shared code)
  2. Services
    • A read-write (write – restricted to only its derivatives) property of type IServiceProviderDI Container
  3. Application
    • A read-write (write – restricted to only its derivatives) property of type IApplication – Nothing but the shared application class instance.

This can be made use of to access the Services from the DI container as mentioned below. The return type is same for all the platforms.

#if ANDROID
    MauiApplication.Current.Services;
#elif IOS || MACCATALYST
    MauiUIApplicationDelegate.Current.Services;
#elif WINDOWS10_0_17763_0_OR_GREATER
    MauiWinUIApplication.Current.Services;
#else
    null;
#endif

To migrate working code from the earlier previews, copy the Windows folder as it is from the WinUI project and paste it into the Platforms folder. Replace the IStartup implementation with the new Abstract based pattern.

To run Windows target, do the necessary changes in the project file as highlighted in the screenshot and the launchSettings.json file is required to be present in the Properties folder. Can be copied from the older project and do the below-mentioned change.

Running Windows Target via WinUI 3 – launchSettings.json

If you come across the issue where the build is successful but deployment not done, then check whether the option is enabled from the Build menu -> Configuration Manager option. Both Build and Deploy checkbox needs to be in a checked state.

Configuration Manager – Build and Deploy

In this post, we’ve seen how .NET MAUI application works in Preview 8 and in the next post, we’ll see the customizations in the CreateMauiApp() method.

Happy coding. Stay connected as we continue to learn and share the experiences from this exciting journey of being a software developer.

5 replies on “.NET MAUI – What’s New in Preview 8”

Comments are closed.