当前位置: 首页 > 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://www.jsqmd.com/news/135424/

相关文章:

  • Hive - SerDe
  • 乌诺地尔vs酮康唑:防脱洗发水怎么选?关键看你的脱发原因 - 速递信息
  • 华为鸿蒙智家新特性推动行业变革,重塑智能家居生态新格局
  • Photoshop进阶基石:“曲线”调色与矢量应用的精髓
  • 收租管理系统软件怎么选?优质公寓管理系统推荐寓盟管家 - 速递信息
  • 二脉通大模型霸屏入选《中国大模型优化领航榜》,成为智能霸屏行业首选! - 品牌智鉴榜
  • 模具设计 | UG软件官方正式版下载与安装教程指南
  • 大数据领域数据服务的数据分析算法应用
  • 2025年AI搜索优化服务商实测榜单:平台覆盖与效果达标率对比 - 速递信息
  • mpv播放器如何快速配置:Windows用户完整入门指南
  • SGrid 创建和可视化一个带有矢量数据(Vector Data)的 3D 结构化网格
  • python+vue美特超市进销存管理系统_91crh
  • 利用AI技术提升论文效率,9款平台开题与降重功能实测推荐
  • 轻松搭建个人知识库:访答软件使用全攻略
  • 科普丨乌诺地尔是什么?与咖啡因、酮康唑相比哪个防脱效果好? - 速递信息
  • 百万医疗保险哪个保险公司的比较好?2025 热门产品精简 QA 指南 - 速递信息
  • 2025银川最新水电暖维修机构TOP5 评测!兴庆、金凤、西夏、贺兰县等地区优质企业权威榜单发布,专业高效解决居家难题 - 全局中转站
  • 【工具】ScreenToGif 视频转动图完整教程
  • gmock 如何mock一个模板类单例
  • 学术写作必备:9个AI平台实测对比,轻松搞定论文从开题到降重
  • 从开题到降重,这9款AI论文平台实测表现优秀,助力学术写作
  • Bazzite 完全攻略:3步打造专业级Linux游戏平台
  • 2025-2026年中国GEO优化公司盘点:综合型与细分型公司对比 - 速递信息
  • 保险怎么买合适年轻人?2025 京东金融专属配置 QA 指南 - 速递信息
  • python+vue的大学生创客创业项目申请答辩平台的设计与实现_4a271
  • python+vue篮球人才球员管理系统vue
  • 星拓广告助力跨境电商圣诞季爆单的三大核心策略 - 速递信息
  • 《人工智能:原理与技术》学习笔记 II —— Reinforcement Learning
  • 解锁AI开发新效率:AI Ping平台与免费明星模型MiniMax-M2.1、GLM-4.7深度解析
  • 技术分享 / 客户 Demo 时,敏感数据防泄露的一种工程化方案