Hello, and Happy new year to you 🥳. In my last article, I did a deep introduction to .Net MAUI. For my first article of the year, we will have an introduction to .NET MAUI handlers. If you are a Xamarin dev, you should know about the “Renderers” architecture. Well, handlers are what replaced renderers when Xamarin Forms evolved to .NET MAUI. But there is so much more about handlers, and today we are here to explore that.
What we will cover
- What is a handler ?
- Why switch to the handler architecture ?
- Understanding the handler architecture
- Using handlers to customize controls
- Modifying every control
- Modifying controls of specific a type
- Modifying an instance of a specific control
What is a .NET MAUI Handler ?
As I mentioned in my previous article, a .NET MAUI handler is an architectural concept used by .NET MAUI to map cross-platform controls to their native implementation. Handlers are used instead of renderers in .NET MAUI because they offer several advantages. Speed, ease of use, easily customizable, etc…
To better understand this introduction to .NET MAUI handlers, it is important that we define some other terms. This will be useful for anyone who wants an introduction to .NET MAUI handlers but isn’t used to Xamarin Forms.
- A Xamarin Forms Renderer is an architectural concept that is used on each platform targeted by Xamarin Forms to create the apropriate control. Note that, every control in Xamarin Forms has its renderer.
- A mapper, is a dictionary inside a handler, to map cross platform APIs to native APIs
Note: .NET MAUI Doesn’t use Renderers. Instead, it has a compatibility layer that allows you to use your former Xamarin Forms renderers without assembly scanning.
Why Switch from Renderers to Handlers ?
Handlers are one of the most attractive features .NET MAUI brings to us. If you are a former Xamarin Forms developer, you should quickly see why after using them. They make life a lot easier, when we want to customize controls, and a lot more. Here are a few points to answer this question.
- Improved Performance; With renderers, reflection and assembly scanning was used to get renderers for the required controls. This process was slow, and had a negative impact on performance. On the other hand, handlers do not need assembly scanning.
- More maintainable code; Handlers are easy to implement and use via the host builder patern of .NET MAUI, they can easily be added to a specific type of control, or every control used in your app.
- It is easier to access and modify native controls directly. With renderers, we had to write a lot of code just to modify the underlying native controls. Handlers make this a lot easier.
- Handlers are easy to implement when compared to all the redundant code required to modify a renderer.
- Every handler’s native controls are not wrapped (Fast Renderers) in some sort of container as it was done in older versions of Xamarin Forms in the past.
To understand better what improvements handlers bring, you can watch this presentation by Javier Suarez.
Understanding the .NET MAUI Handler Architecture
The documentation for .NET MAUI isn’t matured yet, since the framework itself is still under development. So, for this introduction to .Net MAUI handlers, I’ve gone through the source code of .NET MAUI and watched several presentations from the team behind this framework, to distill this information and make it available for you.
Note that, the way handlers are made and customized has changed a few times, and could still change since no release candidate or official release of .NET MAUI has been made yet as of the time of writing this article. If any change occurs, I’ll modify this article as soon as I notice it.
It is important to note that, .NET MAUI’s controls each have an interface representation, that abstracts the native controls. These interfaces are derived from the IView interface. Every handler primarily uses only these control interfaces and touches the underlying control only at the platform level, where it maps properties. Let’s take the label as an example. Here is the ILabel interface implemented by MAUI’s Label.
The code for the above interface and other interfaces for the controls available in .NET MAUI could be found here. The handlers now provide an abstraction layer for these controls. The diagram below, gotten from the docs, highlights this architecture very well.
As mentioned above, each .NET MAUI control inherits from the appropriate interface. The class that implements this interface, contains the appropriate bindable properties, and mappers if necessary. For our label control, you can find the partial classes implementing the ILabel interface here and here too.
NOTE: We will call the controls that implement these interfaces (deriving from the IView interface) “Virtual Views”.
The handler is then responsible for taking the above implementation of ILabel, creating the underlying native control, and map its properties to those of the virtual view. That is it, once you get that, I think everything becomes easier.If you find this article useful, please follow me on Twitter, Github, Linkedin, or like my Facebook page to stay updated.Follow me on social media and stay updated
Every .NET MAUI Handler is derived from the ViewHandler abstract class. As you can see in the image below, this class precises that when targeting platform frameworks, the TNativeView should be a derivative of the NativeView class, and when targeting a .Net standard project, this can be any class. You can see the definition of other abstract methods like “CreateNativeView” by going through the source code here.
The label’s handler is then divided into a set of partial classes, each responsible for specific tasks. We can see below, where the mapper is defined, and specific properties are linked to methods that perform the mapping. The source code for all of these is found here.
For the Android platform, we have the LabelHandler.Android.cs file, containing the code where the native view is created. In our case, this native view is an “AppCompatTextView“. This is the underlying view that is displayed on the UI of your app. The handler makes this view accessible via a property called “NativeView“. You can modify this view as you wish. We will look at that very soon.
You can also see the implementations of the mappings. If you go through these mappings, you’ll notice that extension methods are used to map properties of the virtual views to those of native views.
We also have the “ConnectHandler” method, where default values are set, and it is in this method that events should be subscribed to if needed.
Note: In case an event is needed to be unsubscribed from, the “DisconnectHandler” would have been overridden, and the event would have been unsubscribed from inside this method.
The same thing goes for iOS and other platforms.
Customising Controls with Handlers
The way handlers are used to customize native controls is very easy to understand. There are a set of methods that allow you to modify mappings to native controls after, before the mapping of properties. When you read the unit tests for the extension methods responsible for these modifications, you can see in which case each method could be used.
- “AppendToMapping” modifications done via this method will be run after an existing property mapping.
- “PrependToMapping” modifications done here will be run before an existing mapping.
- “ModifyMapping” modifies an existing mapping.
All of these methods are called in a similar way, they just defer in the order in which our modifications are executed. now, let’s get our hands dirty with some code. An introduction to .NET MAUI Handlers won’t make any sense without a real example.
Modifying every control
Below, we modify every control on Android, and change their background color to Blue.
Microsoft.Maui.Handlers.ViewHandler.ViewMapper.AppendToMapping(nameof(IView.Background), (h, v) =>
(h.NativeView as Android.Views.View).SetBackgroundColor(Microsoft.Maui.Graphics.Colors.Red.ToNative());
NOTE: You can change the key of your mapping to what you wish. See the image below.
NOTE: The code to modify your handler can be called anywhere in your project. It is not tied to a specific location.
Modifying Controls of a Specific type only
Below, we will modify only labels, and make them have a specific background color.
Microsoft.Maui.Handlers.LabelHandler.LabelMapper.PrependToMapping("MyLabelMapping", (h, v) =>
(h.NativeView as AppCompatTextView).SetBackgroundColor(Microsoft.Maui.Graphics.Colors.Yellow.ToNative());
Modifying a specific instance of a control
To modify a specific instance of a control, you will have to create a subclass for that control, and apply the appropriate modifications to it. I took this example from the Microsoft docs here.
public class MyEntry : Entry
Then you modify the controls that are of the type “MyEntry”.
Microsoft.Maui.Handlers.EntryHandler.EntryMapper.AppendToMapping(nameof(IView.Background), (handler, view) =>
if (view is MyEntry)
handler.NativeView.BackgroundColor = Colors.Red.ToNative();
handler.NativeView.BorderStyle = UIKit.UITextBorderStyle.Line;
handler.NativeView.Background = Colors.Red.ToNative();
How do you feel about this handlers architecture? I’ll like to know in the comments section, especially if you are a former Xamarin Forms dev. I for one think it is better than renderers. The only downside is that we have to use pre-processor directives very often in our code, and it is not that beautiful. This problem can easily be solved though. I think I’ll write an article about that. You might also like my post that introduces you deep into .NET MAUI.Follow me on social media and stay updated