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

.NET8 MAUI中CommunityToolkit Popup报错及替代方案咨询

.NET 8 MAUI CommunityToolkit Popup发布异常及替代实现方案

问题回顾

  • 本地调试时CommunityToolkit Popup功能正常,发布至Google Store后触发System.ObjectDisposedException,异常指向CommunityToolkit.Maui.Core.Views.MauiPopup已被释放。
  • 调用ShowPopup后立即执行Close(),Popup无法正常关闭。

异常信息

System.ObjectDisposedException: ObjectDisposed_Generic ObjectDisposed_ObjectName_Name, CommunityToolkit.Maui.Core.Views.MauiPopup

调用堆栈

Java.Interop.JniPeerMembers.AssertSelf(IJavaPeerable )
Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualBooleanMethod(String, IJavaPeerable , JniArgumentValue* )
Android.App.Dialog.get_IsShowing()
CommunityToolkit.Maui.Core.Handlers.PopupHandler.MapOnClosed(PopupHandler handler, IPopup view, Object result)
Microsoft.Maui.CommandMapper`2.<>c__DisplayClass6_0[[CommunityToolkit.Maui.Core.IPopup, CommunityToolkit.Maui.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[CommunityToolkit.Maui.Core.Handlers.PopupHandler, CommunityToolkit.Maui.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].b__0(IElementHandler h, IElement v, Object o)
Microsoft.Maui.CommandMapper.InvokeCore(String key, IElementHandler viewHandler, IElement virtualView, Object args)
Microsoft.Maui.CommandMapper.Invoke(IElementHandler viewHandler, IElement virtualView, String property, Object args)
Microsoft.Maui.Handlers.ElementHandler.Invoke(String command, Object args)
CommunityToolkit.Maui.Views.Popup.CommunityToolkit.Maui.Core.IPopup.OnClosed(Object result)
CommunityToolkit.Maui.Views.Popup.OnClosed(Object result, Boolean wasDismissedByTappingOutsideOfPopup, CancellationToken token)
CommunityToolkit.Maui.Views.Popup.CloseAsync(Object result, CancellationToken token)
CommunityToolkit.Maui.Views.Popup.Close(Object result)
System.Threading.Tasks.Task.<>c.b__128_0(Object state)
Android.App.SyncContext.<>c__DisplayClass2_0.b__0()
Java.Lang.Thread.RunnableImplementor.Run()
Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz)

响应异常场景

执行以下代码后立即调用Close(),Popup无法关闭:

var loadingPopup = new LoadingPopup();
Application.Current.MainPage.ShowPopup(loadingPopup);
loadingPopup.Close(); 

问题排查建议(针对CommunityToolkit异常)

  1. 异步调用修正:ShowPopup本质是异步初始化操作,立即调用Close()会导致Popup尚未完成渲染就被触发关闭,引发资源释放异常。改用异步等待逻辑:
var loadingPopup = new LoadingPopup();
// 使用ShowPopupAsync确保弹窗完成加载
await Application.Current.MainPage.ShowPopupAsync(loadingPopup);
// 或在需要关闭时,通过绑定或延迟确保弹窗已初始化
loadingPopup.Close();
  1. 发布代码裁剪防护:检查Android发布配置,避免R8/ProGuard过度裁剪CommunityToolkit的Popup相关类,在proguard.cfg中添加规则:
-keep class CommunityToolkit.Maui.Core.Views.MauiPopup { *; }
-keep class CommunityToolkit.Maui.Core.Handlers.PopupHandler { *; }
  1. 实例引用维护:确保Popup实例在页面生命周期内保持强引用,避免被GC提前回收导致释放异常。

不依赖CommunityToolkit的跨平台Popup实现方案

方案1:自定义全屏覆盖式Popup(通用跨平台)

通过在当前页面添加半透明覆盖层+弹窗内容的方式实现,完全支持Windows、macOS及其他MAUI平台:

核心实现代码

public class CustomPopup : ContentView
{
    public static readonly BindableProperty IsVisibleProperty =
        BindableProperty.Create(nameof(IsVisible), typeof(bool), typeof(CustomPopup), false, propertyChanged: OnIsVisibleChanged);

    public bool IsVisible
    {
        get => (bool)GetValue(IsVisibleProperty);
        set => SetValue(IsVisibleProperty, value);
    }

    private static void OnIsVisibleChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var popup = (CustomPopup)bindable;
        if ((bool)newValue) popup.Show();
        else popup.Hide();
    }

    private void Show()
    {
        if (Parent != null) return;
        
        var mainPage = Application.Current.MainPage;
        var overlay = new AbsoluteLayout
        {
            BackgroundColor = Color.FromRgba(0, 0, 0, 0.5),
            InputTransparent = false
        };

        // 弹窗居中显示
        AbsoluteLayout.SetLayoutBounds(this, new Rect(0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
        AbsoluteLayout.SetLayoutFlags(this, AbsoluteLayoutFlags.PositionProportional);
        overlay.Children.Add(this);

        // 将覆盖层添加到页面最上层
        mainPage.Content = new AbsoluteLayout
        {
            Children = { mainPage.Content, overlay }
        };
    }

    private void Hide()
    {
        if (Parent is not AbsoluteLayout overlay || overlay.Parent is not AbsoluteLayout parentLayout) return;
        
        parentLayout.Children.Remove(overlay);
        // 恢复原页面内容
        parentLayout.Children.Add((View)parentLayout.Children[0]);
    }

    public void Close() => IsVisible = false;
}

使用示例

// 创建带加载动画的弹窗
var loadingPopup = new CustomPopup
{
    Content = new StackLayout
    {
        WidthRequest = 220,
        HeightRequest = 160,
        BackgroundColor = Colors.White,
        CornerRadius = 12,
        Padding = new Thickness(20),
        Children = 
        {
            new ActivityIndicator { IsRunning = true, Color = Colors.Blue },
            new Label { Text = "加载中...", Margin = new Thickness(0,10,0,0) }
        }
    }
};

// 显示弹窗
loadingPopup.IsVisible = true;

// 关闭弹窗
loadingPopup.Close();

方案2:平台原生API封装(依赖服务)

针对不同平台调用原生弹窗组件,通过MAUI依赖服务实现跨平台适配,适合简单文本类弹窗:

1. 定义接口

public interface IPopupService
{
    Task ShowPopupAsync(string title, string content);
    Task ClosePopupAsync();
}

2. 各平台实现

  • Windows:调用ContentDialog
  • macOS:调用NSAlert
  • Android:调用AlertDialog
  • iOS:调用UIAlertController

这种方案优势是原生体验,缺点是自定义内容灵活性较低,复杂弹窗推荐方案1。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:43:13