NET8 MAUI中CommunityToolkit Popup无法正常关闭问题求助
问题描述
在.NET8 MAUI应用中,我使用CommunityToolkit的Popup服务实现了一个LoadingPopup。页面注入了ViewModel(示例用vm表示),LoadingPopup的XAML代码如下:
<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" x:Class="MyProject.SimplePopup"> <VerticalStackLayout> <Label Text="This is a very important message!" /> </VerticalStackLayout> </toolkit:Popup>
页面的OnAppearing方法中调用ViewModel的初始化逻辑:
protected override async void OnAppearing() { base.OnAppearing(); await vm.Init(); }
ViewModel的Init方法代码如下:
public async Task Init() { if (IsRefreshing) return; IsRefreshing = true; var loadingPopup = new LoadingPopup(); Application.Current.MainPage.ShowPopup(loadingPopup); // step 1: 执行业务操作 loadingPopup.Close(); IsRefreshing = false; }
遇到的问题:
- 当
step 1操作耗时较长时,LoadingPopup能正常显示并关闭; - 当
step 1操作很快时,LoadingPopup会一直停留在界面,调试显示代码执行了显示和关闭逻辑,但实际无效果; - 改用异步方法
await Application.Current.MainPage.ShowPopupAsync(loadingPopup);后,应用会一直处于等待状态。
解决方案
问题根源
- 同步场景下:UI线程还没完成Popup的渲染,就执行了Close操作,导致渲染和关闭逻辑在同一个UI线程周期内执行,最终Popup无法正常关闭;
ShowPopupAsync使用错误:该方法会等待Popup被手动关闭后才继续执行后续代码,直接在调用后执行Close会造成阻塞,引发死等。
具体修复
1. 解决同步场景下Popup无法关闭的问题
在显示Popup后,给UI线程留出渲染时间,再执行后续业务操作:
public async Task Init() { if (IsRefreshing) return; IsRefreshing = true; var loadingPopup = new LoadingPopup(); Application.Current.MainPage.ShowPopup(loadingPopup); // 给UI线程留出渲染Popup的时间 await Task.Delay(1); // step 1: 执行你的业务操作 // 示例:await FetchDataAsync(); loadingPopup.Close(); IsRefreshing = false; }
2. 正确使用ShowPopupAsync方法
将业务操作放在后台线程执行,避免阻塞UI线程和Popup的等待逻辑:
public async Task Init() { if (IsRefreshing) return; IsRefreshing = true; var loadingPopup = new LoadingPopup(); // 后台执行业务操作 var task = Task.Run(async () => { // step 1: 执行你的业务操作 // 示例:await FetchDataAsync(); // 回到UI线程关闭Popup await MainThread.InvokeOnMainThreadAsync(() => loadingPopup.Close()); }); // 等待Popup关闭 await Application.Current.MainPage.ShowPopupAsync(loadingPopup); // 等待后台业务操作完成 await task; IsRefreshing = false; }
3. 封装复用(可选)
可以把LoadingPopup的显示和关闭逻辑封装成通用方法,简化调用:
public static async Task WithLoading(Func<Task> action) { var loadingPopup = new LoadingPopup(); Application.Current.MainPage.ShowPopup(loadingPopup); await Task.Delay(1); try { await action(); } finally { loadingPopup.Close(); } }
在ViewModel中调用:
public async Task Init() { if (IsRefreshing) return; IsRefreshing = true; await WithLoading(async () => { // step 1: 执行你的业务操作 }); IsRefreshing = false; }
内容的提问来源于stack exchange,提问作者Enrico
相关产品推荐
相关产品推荐

