Many apps, whether mobile or desktop, require the ability to show a map. However, .NET MAUI doesn’t currently have a view (control) capable of displaying a map. That’s frustrating because the underlying platforms that .NET MAUI supports all largely have native map views. Android has the MapView
. iOS/MacCatalyst has MKMapView
. WinUI has…nothing.
So, most of the platforms .NET MAUI runs on can display a map, but .NET MAUI itself lacks a cross-platform view to display a map. Therefore I’ve created a very simple cross-platform Map
view. It was written primarily for me to understand how to write handlers, rather than being a fully featured control. It displays a map, lets you scroll it, zoom it, show your location, show traffic data, and change the map imagery (street/satellite/hybrid). There’s plenty it doesn’t do - no initialising the map to a specific location, no map pins, no routes, no drawing on the map surface etc. A fully featured Map
view is beyond the scope of what I was attempting to do, and besides, there will be one appearing in .NET MAUI in the not too distant future.
As it’s a simpler example than the Video
view I published yesterday, I thought I’d share it.
Handler architecture
.NET MAUI has an extension mechanism, known as handlers, that you can use to customise existing .NET MAUI controls, and write your own cross-platform views whose implementations are provided by native views.
Each .NET MAUI view has an interface representation, that abstracts a cross-platform view. Cross-platform views that implement these interfaces are known as virtual views. Handlers map these virtual views to native views on each platform, and are responsible for creating the underlying native view, and mapping their API to the cross-platform control.
Handlers are accessed through their view-specific interface. This avoids the cross-platform view having to reference its handler, and the handler having to reference the cross-platform view. Each handler typically provides a property mapper, and sometimes a command mapper, that maps the cross-platform view API to the native view API.
The following diagram shows the handler architecture for the Map
view:
The Map
view implements the IMap
interface. On iOS/MacCatalyst, the MapHandler
class maps the cross-platform Map
view to an iOS/MacCatalyst MKMapView
. On Android, the Map
view is mapped to a MapView
that's provided by the Xamarin.GooglePlayServices.Maps NuGet package. There’s no Windows implementation, due to the lack of a map control on WinUI.
The PropertyMapper
in the MapHandler
class maps the cross-platform view properties to native view APIs via mapper methods. Each platform then provides implementations of the mapper methods, which manipulate the native view API as appropriate. The overall effect is that when a property is set on the cross-platform view, the underlying native view is updated as required.
Handler implementations on each platform must override the CreatePlatformView
method, and optionally the ConnectHandler
and DisconnectHandler
methods. The CreatePlatformView
method should return the native view that implements the cross-platform view. The ConnectHandler
method should perform any required native view setup, and the DisconnectHandler
method should perform any required native view cleanup. Note that the DisconnectHandler
override is intentionally not invoked by .NET MAUI - you have to invoke it yourself from a suitable place in your app’s lifecycle.
Code
I’m not going to provide a walkthrough of the code. But you can download it, and step through it yourself, by cloning the repo. However, I will give you some pointers to working through the code.
The important files in the solution are highlighted below:
- Controls - the cross-platform view implementation.
IMap
abstracts theMap
view and exposes members that the handler needs to be able to access, and derives from .NET MAUI’sView
. TheMap
class, which derives from .NET MAUI’sView
class, provides the cross-platform implementation, and is simply a collection ofBindableProperty
objects. - Handlers - The
IMapHandler
interface, which derives from .NET MAUI’sIViewHandler
, specifiesVirtualView
andPlatformView
properties. TheVirtualView
property is used to access the cross-platform view from the handler, and thePlatformView
property is used to access the native view that implements theMap
view. TheMapHandler
class is a partial class, whose platform-specific implementations are in the MapHandler.Android.cs, MapHandler.iOS.cs and MapHandler.Windows.cs files.
A handler must be registered against its cross-platform view, and this takes place in MauiProgram.cs with the ConfigureMauiHandler
/AddHandler
methods.
On Android you’ll need to insert your Google Map API key into the Android Manifest for the map to appear.
I hope this ends up being useful to folks on their journey to understand how to write custom controls backed by .NET MAUI handlers.
No comments:
Post a Comment