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

.NET MAUI中获取数据后等待再导航的正确实现方式(C#)

问题分析与解决

你的核心问题在于异步操作的不当处理导致导航提前触发,以及冗余的主线程调用可能引发的时序问题。以下是针对性的修正方案:

关键问题点

  1. 使用async void导致无法正确等待异步操作完成:原代码在OnNavigatedTo中通过MainThread.BeginInvokeOnMainThread传入async void lambda,这种方式属于"fire-and-forget",框架无法跟踪异步任务的完成状态,极端情况下可能导致导航提前执行。
  2. 冗余的MainThread调用:在已处于主线程的上下文中重复调用MainThread.BeginInvokeOnMainThread,会导致UI更新延迟或时序混乱。
  3. 未正确管理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é

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:07:22