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

MAUI复用Xamarin Forms渲染器时CreateRendererWithContext抛出异常

MAUI迁移:兼容包复用渲染器时CreateRendererWithContext抛出异常

问题场景

从Xamarin.Forms迁移至MAUI多项目架构时,使用MAUI兼容包复用原有自定义渲染器,调用CreateRendererWithContext创建内部页面渲染器时抛出FragmentManager事务冲突异常。


相关代码文件

MauiProgram.cs(Android项目)

using System;
using Microsoft.Maui.Controls.Compatibility.Hosting;

namespace LibraryTestAppMaui.Android
{
    public static class MauiProgram
    {
        public static MauiAppBuilder builder;
        public static MauiAppBuilder Builder
        {
            get
            {
                if (builder == null)
                {
                    builder = MauiApp.CreateBuilder();
                }

                return builder;
            }
        }
        public static MauiApp CreateMauiApp()
        {
            var builder = Builder;
            builder
                .UseMauiCompatibility()
                .UseMauiApp<App>();

            builder.ConfigureMauiHandlers(handlers => {
#if ANDROID
                handlers.AddHandler(typeof(KeyboardWrapperPage), typeof(KeyboardWrapperPageRenderer));
#endif
            });
            builder.Services.AddTransient<MainPage>();
            return builder.Build();
        }
    }
}

App.Xaml.cs

using System;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace LibraryTestAppMaui
{
    public partial class App : Application
    {
        public static new App Current => (App)Application.Current;

        public App ()
        {
            InitializeComponent();
            MainPage = CreateMainPage(new NavigationPage());
        }

        private Page CreateMainPage(NavigationPage navigationPage)
        {
            return new KeyboardWrapperPage(navigationPage);
        }

        protected override void OnStart () {}
        protected override void OnSleep () {}
        protected override void OnResume () {}
       
    }
}

KeyboardWrapperPage

using System;
namespace LibraryTestAppMaui
{
    public class KeyboardWrapperPage : Page, IPageContainer<Page>
    {
        public KeyboardWrapperPage(Page innerPage)
        {
            BackgroundColor = Colors.White;
            CurrentPage = innerPage;
            InternalChildren.Add(innerPage);
        }

        public Page CurrentPage { get; }

        protected override bool OnBackButtonPressed()
        {
            return CurrentPage.SendBackButtonPressed();
        }
    }
}

KeyboardWrapperPageRenderer(Android)

using System;
using Android.Content;
using Android.Views;
using Android.Widget;
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Platform;
using AndroidPlatform = Microsoft.Maui.Controls.Compatibility.Platform.Android.Platform;

namespace LibraryTestAppMaui.Android
{
    public class KeyboardWrapperPageRenderer : Microsoft.Maui.Controls.Handlers.Compatibility.VisualElementRenderer<KeyboardWrapperPage>
    {
        bool disposed;
        FrameLayout pageContainer;
        IPageController PageController => Element;

        int KEYBOARD_HEIGHT => (int)Context.Resources.GetDimension(260);

        public KeyboardWrapperPageRenderer(Context context) : base(context)
        {
            AutoPackage = false;
        }

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

            if (e.NewElement != null)
            {
                var bottomBarPage = e.NewElement;

                if (pageContainer == null)
                {
                    pageContainer = CreatePageContainer(Context);
                    AddView(pageContainer);
                    RequestLayout();
                }

                UpdateContent();
            }
        }

        protected override void OnAttachedToWindow()
        {
            base.OnAttachedToWindow();
            PageController.SendAppearing();
        }

        protected override void OnDetachedFromWindow()
        {
            base.OnDetachedFromWindow();
            PageController.SendDisappearing();
        }

        void UpdateContent()
        {
            pageContainer.RemoveAllViews();
            var page = Element?.CurrentPage;
            if (page != null)
            {
                pageContainer.AddView(GetRenderer(page, Context).View);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && !disposed)
            {
                disposed = true;
                RemoveAllViews();
                var pageRenderer = AndroidPlatform.GetRenderer(Element.CurrentPage);
                if (pageRenderer != null)
                {
                    pageRenderer.View.RemoveFromParent();
                    pageRenderer.Dispose();
                }
                pageContainer?.Dispose();
            }
            base.Dispose(disposing);
        }

        static FrameLayout CreatePageContainer(Context context)
        {
            return new FrameLayout(context)
            {
                LayoutParameters = new FrameLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent, GravityFlags.Fill)
            };
        }

        static IVisualElementRenderer GetRenderer(VisualElement element, Context context)
        {
            var renderer = AndroidPlatform.GetRenderer(element);
            if (renderer == null)
            {
                renderer = AndroidPlatform.CreateRendererWithContext(element, context);
                AndroidPlatform.SetRenderer(element, renderer);
            }
            return renderer;
        }
    }
}

异常详情

Android.Views.InflateException: Binary XML file line #1 in com.companyname.librarytestappmaui:layout/fragment_backstack: Error inflating class androidx.fragment.app.FragmentContainerView
---> Java.Lang.IllegalStateException: FragmentManager is already executing transactions …


解决方案

1. 延迟渲染器创建,避免事务冲突

异常核心原因是OnElementChanged执行时,MAUI内部正在处理Fragment事务,此时手动创建渲染器会触发新的Fragment操作,导致冲突。将UpdateContent延迟到主线程消息队列末尾执行:

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

    if (e.NewElement != null)
    {
        var bottomBarPage = e.NewElement;

        if (pageContainer == null)
        {
            pageContainer = CreatePageContainer(Context);
            AddView(pageContainer);
            RequestLayout();
        }

        // 延迟执行,避开当前Fragment事务周期
        Post(() => UpdateContent());
    }
}

2. 简化渲染器生命周期管理

移除Dispose中手动操作渲染器父视图的逻辑,依赖MAUI兼容包自动处理渲染器生命周期,避免破坏内部Fragment状态:

protected override void Dispose(bool disposing)
{
    if (disposing && !disposed)
    {
        disposed = true;
        pageContainer?.RemoveAllViews();
        pageContainer?.Dispose();
        pageContainer = null;
    }
    base.Dispose(disposing);
}

3. 优化页面封装逻辑

避免直接封装NavigationPage,改为让KeyboardWrapperPage继承NavigationPage,复用MAUI原生的导航页渲染逻辑,减少自定义渲染器的复杂度:

public class KeyboardWrapperPage : NavigationPage
{
    public KeyboardWrapperPage(Page innerPage) : base(innerPage)
    {
        BackgroundColor = Colors.White;
    }

    protected override bool OnBackButtonPressed()
    {
        return CurrentPage.SendBackButtonPressed();
    }
}

4. 确保版本一致性

检查Microsoft.Maui.Controls.Compatibility包版本与MAUI主包版本完全一致,避免版本不匹配导致的底层API冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:33:12