You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms视图渲染器迁移至.NET MAUI遇阻,求解决方案

.NET MAUI迁移Camera2自定义视图问题排查与解决方案

原Xamarin.Forms代码

共享项目自定义View

public class CameraRecordV3 : View
{
    public static readonly BindableProperty StartProperty = BindableProperty.Create(
        "Start", typeof(int), typeof(int), 6000);

    public int Start
    {
        set { SetValue(StartProperty, value); }
        get { return (int)GetValue(StartProperty); }
    }
}

Android平台渲染器

using iVue.Views;
using System.ComponentModel;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Controls.Handlers.Compatibility;

namespace iVue.Platforms.Android.Renderers;

public class CameraRecordRenderer_V3 : ViewRenderer<CameraRecordV3, CameraRecordControl_V3>
{
    private CameraRecordControl_V3 _cameraControl;
    private DisplayTimeHelper _displayTimeHelper = new DisplayTimeHelper();

    public CameraRecordRenderer_V3(Context context)
      : base(context)
    {
    }

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

        if (Control == null)
        {
            _cameraControl = new CameraRecordControl_V3(Context, e.NewElement);
            SetNativeControl(_cameraControl);
        }
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var model = (CameraRecordV3)sender;
        base.OnElementPropertyChanged(sender, e);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (disposing)
        {
            _cameraControl.Dispose();
            if(Control != null)
                Control.Dispose();
        }
    }
}

Android原生ViewGroup(CameraRecordControl_V3)

public class CameraRecordControl_V3 : ViewGroup
{
    public CameraRecordControl_V3(Context context, CameraRecordV3 vm) : base(context)
    {
        _activity = this.Context as Activity;
        _view = _activity.LayoutInflater.Inflate(Resource.Layout.CameraRecordLayoutV2, this, false);
        AddView(_view);

        _toolbar = (Toolbar)_view.FindViewById(Resource.Id.toolbar);
        textureView = (AutoFitTextureView)_view.FindViewById(Resource.Id.textureview);
        _questionTitleView = (Button)_view.FindViewById(Resource.Id.Start);
    }
}

迁移的.NET MAUI代码

共享项目代码

public interface ICameraRecordV3 : IView 
{   
    public int StartTime { get; }
}

public partial class CameraRecordV3Handler
{
    public static PropertyMapper<ICameraRecordV3, CameraRecordV3Handler> CustomMapper 
        = new PropertyMapper<ICameraRecordV3, CameraRecordV3Handler>(ViewHandler.ViewMapper)
    {
        [nameof(ICameraRecordV3.StartTime)] = MapStartTime,
    };

    public CameraRecordV3Handler() : base(CustomMapper)
    {

    }

    public CameraRecordV3Handler(PropertyMapper mapper = null) : base(mapper ?? CustomMapper)
    {

    }
}

public class CameraRecordV3 : View, ICameraRecordV3 
{
    public static readonly BindableProperty StartTimeProperty = BindableProperty.Create(
        "StartTime", typeof(int), typeof(int), 6000);

    public int Start
    {
        set { SetValue(StartTimeProperty, value); }
        get { return (int)GetValue(StartTimeProperty); }
    }
}

Android平台Handler

public partial class CameraRecordV3Handler : ViewHandler<ICameraRecordV3, CameraRecordControl_V3>
{
    private CameraRecordControl_V3 _cameraControl;
    protected override CameraRecordControl_V3 CreatePlatformView()
    {
        _cameraControl = new CameraRecordControl_V3(Context, null);
        return _cameraControl;
    }

    protected override void ConnectHandler(CameraRecordV3 platformView)
    {
        base.ConnectHandler(platformView);           
    }

    private static void MapStartTime(CameraRecordV3Handler handler, ICameraRecordV3 arg2)
    {
        handler.PlatformView?.UpdateStartTime(arg2.StartTime);
    }
}

MauiProgram配置

builder.ConfigureMauiHandlers(handlers =>
{
    #if __ANDROID__
    handlers.AddHandler(typeof(CameraRecordV3), typeof(iVue.Handlers.CameraRecordV3Handler));
    #endif
});

问题排查与修正方案

1. 统一BindableProperty与属性命名

MAUI代码中BindableProperty、CLR属性、接口属性名称不统一,导致属性变更无法正确映射。
修正:

public class CameraRecordV3 : View, ICameraRecordV3 
{
    public static readonly BindableProperty StartTimeProperty = BindableProperty.Create(
        nameof(StartTime), typeof(int), typeof(int), 6000);

    public int StartTime
    {
        set { SetValue(StartTimeProperty, value); }
        get { return (int)GetValue(StartTimeProperty); }
    }
}

2. 传递ViewModel实例到原生控件

原Xamarin渲染器会传入CameraRecordV3实例,MAUI Handler当前传入null,导致原生控件无法获取共享视图的属性。
修正:

protected override CameraRecordControl_V3 CreatePlatformView()
{
    var cameraView = VirtualView as CameraRecordV3;
    _cameraControl = new CameraRecordControl_V3(Context, cameraView);
    return _cameraControl;
}

3. 补充资源释放与初始属性映射

MAUI Handler需要实现资源释放逻辑,并确保初始属性值传递到原生控件。
修正:

protected override void ConnectHandler(CameraRecordControl_V3 platformView)
{
    base.ConnectHandler(platformView);
    // 触发初始属性映射
    MapStartTime(this, VirtualView);
}

protected override void DisconnectHandler(CameraRecordControl_V3 platformView)
{
    base.DisconnectHandler(platformView);
    platformView?.Dispose();
    _cameraControl?.Dispose();
}

4. 实现原生控件的属性更新方法

Handler中调用的UpdateStartTime方法在原生控件中未定义,需要补充实现:

public class CameraRecordControl_V3 : ViewGroup
{
    // 原有代码...

    public void UpdateStartTime(int startTime)
    {
        // 根据业务需求更新UI或逻辑,例如设置按钮文本
        // _questionTitleView.Text = $"倒计时:{startTime/1000}秒";
    }
}

5. 验证Handler注册命名空间

检查MauiProgram中Handler的命名空间是否与实际定义的CameraRecordV3Handler完全一致,避免注册失败。

内容的提问来源于stack exchange,提问作者Sonali Rane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:30:22