.NET MAUI中获取数据后等待再导航的正确实现方式(C#)
问题分析与解决
你的核心问题在于异步操作的不当处理导致导航提前触发,以及冗余的主线程调用可能引发的时序问题。以下是针对性的修正方案:
关键问题点
- 使用
async void导致无法正确等待异步操作完成:原代码在OnNavigatedTo中通过MainThread.BeginInvokeOnMainThread传入async voidlambda,这种方式属于"fire-and-forget",框架无法跟踪异步任务的完成状态,极端情况下可能导致导航提前执行。 - 冗余的
MainThread调用:在已处于主线程的上下文中重复调用MainThread.BeginInvokeOnMainThread,会导致UI更新延迟或时序混乱。 - 未正确管理
IsBusy状态:仅设置IsBusy = true但未在操作完成后重置,可能导致UI状态异常。
正确实现方式
1. 切换到IAsyncNavigationAware接口
Prism提供了IAsyncNavigationAware接口,支持异步的导航生命周期方法,避免async void带来的问题。
2. 简化异步逻辑与UI更新
移除冗余的MainThread调用,利用.NET MAUI默认的同步上下文,确保await后的代码自动回到主线程执行。
修正后的完整代码
using Prism.Navigation; using System.Diagnostics; using System.Threading.Tasks; public class LoadingPageViewModel : ViewModelBase, IAsyncNavigationAware { private bool _isBusy; public bool IsBusy { get => _isBusy; set => SetProperty(ref _isBusy, value); } private string _loadingText; public string LoadingText { get => _loadingText; set => SetProperty(ref _loadingText, value); } public async Task OnNavigatedToAsync(INavigationParameters parameters, NavigationMode mode) { IsBusy = true; try { await GetCatalogs(); // 所有请求完成后再导航 await Navigation.NavigateAsync("app:///NavigationPage/MainPage"); } finally { IsBusy = false; } } private async Task GetCatalogs() { try { LoadingText = "Loading Vendors..."; AppSingleton.ApbCatalog = await AppSingleton.ApiService.GetApbCatalog(); LoadingText = "Loading Produce Catalog..."; AppSingleton.ProduceCatalog = await AppSingleton.ApiService.GetProduceCatalog(); LoadingText = "Loading Generic Catalog..."; AppSingleton.GenericCatalog = await AppSingleton.ApiService.GetGenericCatalog(); } catch (Exception ex) { Debug.WriteLine($"加载失败: {ex.Message}"); // 可选:添加错误提示逻辑,例如弹出Toast或Alert // await PageDialogService.DisplayAlert("错误", "数据加载失败,请重试", "确定"); } } public Task OnNavigatedFromAsync(INavigationParameters parameters) { return Task.CompletedTask; } }
额外优化建议
- 并行加载(可选):如果三个接口之间没有依赖关系,可使用
Task.WhenAll并行加载以提升速度,同时通过ContinueWith跟踪每个任务的完成状态来更新加载文本:private async Task GetCatalogs() { try { LoadingText = "Loading Vendors..."; var vendorTask = AppSingleton.ApiService.GetApbCatalog().ContinueWith(t => { AppSingleton.ApbCatalog = t.Result; LoadingText = "Loading Produce Catalog..."; }, TaskScheduler.FromCurrentSynchronizationContext()); var produceTask = AppSingleton.ApiService.GetProduceCatalog().ContinueWith(t => { AppSingleton.ProduceCatalog = t.Result; LoadingText = "Loading Generic Catalog..."; }, TaskScheduler.FromCurrentSynchronizationContext()); var genericTask = AppSingleton.ApiService.GetGenericCatalog().ContinueWith(t => { AppSingleton.GenericCatalog = t.Result; }, TaskScheduler.FromCurrentSynchronizationContext()); await Task.WhenAll(vendorTask, produceTask, genericTask); } catch (Exception ex) { Debug.WriteLine($"加载失败: {ex.Message}"); } } - 错误处理增强:在捕获异常后,可添加用户提示逻辑,避免静默失败导致用户困惑。
内容的提问来源于stack exchange,提问作者Le Fernandé
相关产品推荐
相关产品推荐

