xamarin.formsmauicustom-renderer

Converting CustomRenderer to CustomHandler in Maui


I have been watching videos and looking up sample code but I am unable to figure out how to do this the right way.

[Porting custom renders to handlers]

(https://github.com/dotnet/maui/wiki/Porting-Custom-Renderers-to-Handlers) Now I have read the Assembly ExportRender has to be removed, found this in the above link. But the example does not match my code, not in a way I can link it together..

This is what worked in my Xamarin.Forms project:

using Android.Content;
using Android.Text;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(App.Views.NumericEntry), typeof(App.Android.NumericEntryRenderer))]

namespace App.Android
{
    public class NumericEntryRenderer : EntryRenderer
    {
        public NumericEntryRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.InputType = InputTypes.ClassNumber | InputTypes.NumberFlagDecimal;
            }
        }
    }
}

This is what I have now, which is not correct as I cannot find the 'OnElementChanged'

using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Handlers;
using App.Controls.Interfaces;
using App.Views;

namespace App.Platforms.Android
{
    public partial class NumericEntryHandler : ViewHandler<INumericEntry, NumericEntry>
    {
        public static PropertyMapper<INumericEntry, NumericEntry> NumericEntryMapper = new PropertyMapper<INumericEntry, NumericEntryHandler>(ViewHandler.ViewMapper)
        {
            [nameof(INumericEntry.Control)] = MapControl,
        };


        protected override NumericEntry CreatePlatformView()
        {
            return new NumericEntry(Context);
        }

        static void MapControl(NumericEntryHandler handler, INumericEntry entry)
        {
            handler.PlatformView.Control = entry.Control;
        }


        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.InputType = InputTypes.ClassNumber | InputTypes.NumberFlagDecimal;
            }
        }
    }
}

If anyone could help me, this would be greatly appreciated as I cannot find anything elsewhere. Thanks


Solution

  • According to your code used in the xamarin's custom renderer. You has no complex job to do with the custom handler. So you can just implement the EntryHandler to do what you want. Such as:

    namespace Xynaps.App.Platforms.Android
    {
          public class NumericEntryHandler : Microsoft.Maui.Handlers.EntryHandler
          {
                protected override void ConnectHandler(AppCompatEditText platformView)
                {
                      base.ConnectHandler(platformView);
                      PlatformView.InputType = InputTypes.ClassNumber | InputTypes.NumberFlagDecimal;
                }
          }
    }
    

    And use the custom handler in the MauiProgram.cs:

    var builder = MauiApp.CreateBuilder();
                builder
                      .UseMauiApp<App>()
                      .ConfigureMauiHandlers(handlers =>
                      {
    #if ANDROID
                            handlers.AddHandler(typeof(NumericEntry), typeof(Xynaps.App.Platforms.Android.NumericEntryHandler));
    #endif
                      });
    

    Update1:

    You can put the code in the Custom Renderer's OnElementChanged method into the Custom Handler's ConnectHandler method. The platformView in the CustomHandler is the Control in the CustomRenderer.

    Update2:

    Because the entry's handler and mapper doesn't contain the InputType property to map the native control's InputType value to the entry. So when you use PlatformView.InputType = InputTypes.ClassNumber | InputTypes.NumberFlagDecimal;, the entry's InputType is always the default value(ClassText).

    So you may need to set it in the ContentPage's OnHandlerChanged method. Such as:

    In the page.xaml:

    <NumericEntry x:Name="myentry" />
    

    In the page.cs:

          protected override void OnHandlerChanged()
          {
                base.OnHandlerChanged();
    #if ANDROID
                (myentry.Handler.PlatformView as AndroidX.AppCompat.Widget.AppCompatEditText).InputType = Android.Text.InputTypes.ClassNumber | Android.Text.InputTypes.NumberFlagDecimal;
    #endif
          }
    

    You can also add the property mapper in your custom handler and set it in the custom handler's ConnectHandler method.