当前位置: 首页 > news >正文

[MAUI]简单可食用的PopupTResult

缘起

2025-12-24 21:35:30 星期三
MAUI没有Popup,百度也找不到大佬的现成轮子。
CommunityToolkits 实现的 Popup 有严重的内存泄露问题,本想仿写 CommunityToolkits 源码实现,未果。
问了下通义,发现轮子雏形挺简洁,根本不需要 CommunityToolkits 那一套。
以下是重新封装成 可传出<TResult>的轮子。

Popup容器
PopupPage.xaml.cs
PopupPage.xaml

Popup
Popup.cs

成果
使用示例

Popup

PopupPage.xaml.cs
static class PopupPageExtension
{public static Task<Popup<TResult>.PopupResult> ShowAsync<TResult>(this Popup<TResult> popup, Page invoker){var page = new PopupPage(popup);invoker.Navigation.PushModalAsync(page);return page.Popup.WaitResultTask as Task<Popup<TResult>.PopupResult>;}
}
/// <summary>
/// 这是包装,请勿食用
/// </summary>
partial class PopupPage : ContentPage
{public PopupPage(ContentView popup){InitializeComponent();mOverlay.Opacity = 0;mBorder.Content = popup;mBorder.Scale = 0.01;}protected override void OnAppearing(){base.OnAppearing();Montages(false);}async Task Montages(bool onDismiss){if (!onDismiss){var t1 = mOverlay.FadeTo(1, 150);var t2 = mBorder.ScaleTo(1, 200, Easing.CubicOut);await Task.WhenAny(t1, t2);}else{var t1 = mOverlay.FadeTo(0, 150, Easing.CubicOut);var t2 = mBorder.ScaleTo(0.01, 150);await Task.WhenAny(t1, t2);}}protected override void OnNavigatedTo(NavigatedToEventArgs args){base.OnNavigatedTo(args);}private async void OnOverlayTapped(object sender, EventArgs e){(sender as VisualElement).IsEnabled = false;try{await CloseAsync(true);}finally{(sender as VisualElement).IsEnabled = true;}}public interface IPopup{bool TrySetResult();bool TrySetCancel();object WaitResultTask { get; }void OnClose();}public IPopup Popup => mBorder.Content as IPopup;public async Task CloseAsync(bool isCanceled){NavigatedFrom += isCanceled? IsCanceled_NavigatedFrom: SetResult_NavigatedFrom;await Montages(true);await Navigation.PopModalAsync();}static void IsCanceled_NavigatedFrom(object sender, NavigatedFromEventArgs e){var This = sender as PopupPage;This.NavigatedFrom -= IsCanceled_NavigatedFrom;This.Popup.TrySetCancel();This.Popup.OnClose();}static void SetResult_NavigatedFrom(object sender, NavigatedFromEventArgs e){var This = sender as PopupPage;This.NavigatedFrom -= SetResult_NavigatedFrom;This.Popup.TrySetResult();This.Popup.OnClose();}
}
PopupPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="PopupPage"x:ClassModifier="internal"BackgroundColor="#50000000"><Gridx:Name="mOverlay"BackgroundColor="#80000000"Opacity="1"><!-- 遮罩层(点击关闭) --><Grid.GestureRecognizers><TapGestureRecognizer Tapped="OnOverlayTapped" /></Grid.GestureRecognizers><!-- Popup 内容容器 --><Border x:Name="mBorder"HorizontalOptions="Center"VerticalOptions="Center"><Label Text="找我有啥事?"/></Border></Grid>
</ContentPage>
Popup.cs
namespace ZhuSheng.Gpr.Controls.Popup;/// <summary>
/// 这是容器,请继承使用。
/// </summary>
abstract class Popup<TResult> : ContentView, PopupPage.IPopup
{public record class PopupResult(bool IsCanceled, TResult Result);public TResult Result { get; protected set; }/// <summary>/// 这个是给 用户 等待用的。/// 等待结束时,Popup 必须已经销毁了。/// 所以 ResultTask.Set 只能在 NavigatedFrom 调用。/// </summary>readonly TaskCompletionSource<PopupResult> ResultTask = new();Task<PopupResult> WaitResult => ResultTask.Task;#region IPopupobject PopupPage.IPopup.WaitResultTask => WaitResult;bool PopupPage.IPopup.TrySetResult(){return ResultTask.TrySetResult(new PopupResult(false, Result));}bool PopupPage.IPopup.TrySetCancel(){return ResultTask.TrySetResult(new PopupResult(true, Result));}public abstract void OnClose();#endregionPopupPage GetPopupPage(){var parent = Parent;while(parent is not null){if (parent is PopupPage page)return page;parent = parent.Parent;}return null;}protected async Task CloseAsync(bool isCanceled){var page = GetPopupPage();await page.CloseAsync(isCanceled);}/// <summary>/// 用户取消/// </summary>public async Task CloseAsync() => await CloseAsync(true);
}
使用示例
partial class LoginPopup : Popup<UserInfo>
{public LoginPopup(){InitializeComponent();// TODO}public override void OnClose(){// TODO}
}

image

http://icebutterfly214.com/news/144858/

相关文章:

  • 当AI Agent学会“打电话“——微软Agent Framework的A2A与AGUI协议深度解析
  • fanxiudlg
  • 华为鸿蒙智家新特性推动行业变革,重塑智能家居生态新格局
  • 断点调式
  • 9个AI论文工具推荐,研究生轻松搞定学术写作!
  • 吴恩达深度学习课程四:计算机视觉 第三周:检测算法 (三)交并比、非极大值抑制和锚框
  • 基于SpringBoot的流浪狗管理系统的设计与构建
  • 2025年AI搜索优化服务商实测榜单:平台覆盖与效果达标率对比 - 速递信息
  • 技术分享 / 客户 Demo 时,敏感数据防泄露的一种工程化方案
  • 9大AI论文平台实测对比:开题报告撰写与降重效果深度评测
  • 精选9款AI论文助手:高效完成开题报告与论文降重任务
  • 【创建计算机断层扫描金属制品】创建的计算机断层扫描金属伪影、该模拟为平行束CT附Matlab代码
  • Java毕设项目推荐-基于springboot的滑雪线上购票售票系统设计与实现基于SpringBoot的现代化滑雪场管理系统设计与实现【附源码+文档,调试定制服务】
  • 《道德情操论》
  • 西门子S7-200PLC玩转自动售货机(五种货物实战)
  • RAG系统上下文精度评估:从理论到实践的完整指南
  • 【开题答辩全过程】以 基于springboot的社区志愿者服务管理系统的设计与实现为例,包含答辩的问题和答案
  • 拒绝流水账!手把手教你用“沁言学术+DeepSeek”构建满分论文工作流
  • Java计算机毕设之基于springboot的滑雪售票系统设计与实现vue和springboot框架开发的滑雪场售票系统设计与实现(完整前后端代码+说明文档+LW,调试定制等)
  • 【计算机毕业设计案例】基于springboot+vue的企业项目合同信息系统基于springboot的合同信息管理系统(程序+文档+讲解+定制)
  • 【毕业设计】基于springboot的合同信息管理系统(源码+文档+远程调试,全bao定制等)
  • AI Agent记忆工程完全指南:从上下文到智能协作
  • 柯萨奇病毒及其重组蛋白:结构、生命周期与科研工具解析
  • 金豺优化算法在冷热电联供系统调度中的应用
  • Linux 内核驱动-中断
  • 实用指南:从0-1了解【火山引擎公有云】
  • 如何快速掌握电路设计:DIY Layout Creator完整使用指南
  • 基于大模型的医疗文本信息抽取技术,推动医疗行业向更加智能化、精准化和个性化的方向发展
  • 告别“硬堆料”时代:摩尔线程全功能GPU的技术路线图与生态突围样本
  • 使用 PHP RdKafka 扩展进行 Kafka 操作详细指南