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

.NET MAUI ViewModel异步数据初始化的最佳实践

.NET MAUI MVVM异步数据初始化最佳实践

方案1:利用页面OnAppearing生命周期事件

这是最直观的实现方式,借助页面的OnAppearing事件触发ViewModel的异步加载逻辑,同时添加标记避免页面重复出现时重复请求数据:

改造ViewModel:

public class BotsViewModel : ObservableObject
{
    private readonly UiPathService _uiPathService;
    private bool _hasLoadedData; // 标记是否已经加载过数据

    public string Title { get; set; } = "UiPath Bots";

    public BotsViewModel(UiPathService uiPathService)
    {
        _uiPathService = uiPathService;
    }

    public async Task LoadInitialDataAsync()
    {
        if (_hasLoadedData) return;
        
        try
        {
            // 执行你的API请求逻辑
            await GetTopBotsByLoSAsync();
            _hasLoadedData = true;
        }
        catch (Exception ex)
        {
            // 这里处理异常,比如给用户显示错误提示
            // 比如设置ErrorMsg属性绑定到页面的提示控件
        }
    }

    private async Task GetTopBotsByLoSAsync()
    {
        // 原有的异步API调用逻辑
        // 比如:TopBots = await _uiPathService.FetchTopBotsAsync();
    }
}

页面后台代码:

public partial class BotsPage : ContentPage
{
    private readonly BotsViewModel _viewModel;

    public BotsPage(BotsViewModel viewModel)
    {
        InitializeComponent();
        _viewModel = viewModel;
        BindingContext = viewModel;
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        await _viewModel.LoadInitialDataAsync();
    }
}

方案2:用CommunityToolkit.Mvvm的异步初始化(推荐)

如果你已经在用Microsoft.Toolkit.Mvvm(官方MVVM工具包),可以直接实现IAsyncInitializable接口(.NET 8及以上支持),或者用AsyncRelayCommand绑定页面加载事件:

先确保安装NuGet包:

Install-Package Microsoft.Toolkit.Mvvm

ViewModel实现:

public class BotsViewModel : ObservableObject, IAsyncInitializable
{
    private readonly UiPathService _uiPathService;

    public string Title { get; set; } = "UiPath Bots";

    public BotsViewModel(UiPathService uiPathService)
    {
        _uiPathService = uiPathService;
    }

    // 实现IAsyncInitializable接口的初始化方法
    public async Task InitializeAsync(CancellationToken cancellationToken)
    {
        await GetTopBotsByLoSAsync();
    }

    private async Task GetTopBotsByLoSAsync()
    {
        // 原有的API调用逻辑
    }
}

在页面中触发初始化:

因为构造函数不能异步,所以可以在页面构造函数中触发,或者在OnAppearing里:

public partial class BotsPage : ContentPage
{
    public BotsPage(BotsViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
        
        // 触发异步初始化,用_ = 避免编译器警告,同时要确保异常被处理
        _ = viewModel.InitializeAsync(CancellationToken.None);
    }
}

方案3:绑定页面Loaded事件到ViewModel命令

如果不想写页面后台代码,可以直接在XAML里把页面的Loaded事件绑定到ViewModel的异步命令:

ViewModel添加命令:

public class BotsViewModel : ObservableObject
{
    private readonly UiPathService _uiPathService;
    private bool _hasLoadedData;

    public IAsyncRelayCommand LoadDataCommand { get; }

    public string Title { get; set; } = "UiPath Bots";

    public BotsViewModel(UiPathService uiPathService)
    {
        _uiPathService = uiPathService;
        LoadDataCommand = new AsyncRelayCommand(LoadInitialData);
    }

    private async Task LoadInitialData()
    {
        if (_hasLoadedData) return;
        
        await GetTopBotsByLoSAsync();
        _hasLoadedData = true;
    }

    private async Task GetTopBotsByLoSAsync()
    {
        // 原有的API调用逻辑
    }
}

XAML绑定:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourApp.Views.BotsPage"
             Loaded="{Binding LoadDataCommand}">
    <!-- 页面内容 -->
</ContentPage>

核心注意事项:

  • 绝对不要在构造函数里直接调用未等待的异步方法:会导致异常无法捕获、线程上下文混乱,甚至视图还没准备好就修改绑定数据引发错误。
  • 一定要加重复加载防护:用_hasLoadedData这类标记,避免页面多次显示时重复请求API。
  • 异常处理不能少:异步方法里必须捕获异常,否则静默失败会让你很难排查问题。

内容的提问来源于stack exchange,提问作者Francisco José Goñi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 11:21:02