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

Blazor WASM MVVM模式下如何自动异步初始化ViewModel数据(禁用代码后置)

Blazor WASM MVVM模式下如何自动异步初始化ViewModel数据(禁用代码后置)

嗨,我刚好碰到过一模一样的场景,给你两个完全符合要求的解决方案——都是只需要修改ViewModel就能实现自动异步加载,不用碰视图或者代码后置:

方案一:结合INotifyPropertyChanged实现自动更新(最推荐)

MVVM模式本身就依赖属性变更通知来同步视图和数据,我们可以利用这个特性来实现自动加载。核心思路是:在ViewModel构造函数里启动异步加载任务,等数据获取完成后更新Items并触发属性变更事件,Blazor会自动监听这个事件并刷新视图。

修改后的ViewModel代码如下:

using System.ComponentModel;
using System.Runtime.CompilerServices;

private readonly IItemService _service;
private List<Item> _items = [];
private bool _isLoading;
private string? _errorMessage;

public event PropertyChangedEventHandler? PropertyChanged;

public IndexViewModel(IItemService service)
{
    _service = service;
    // 启动异步初始化任务,用_ = 避免异步"火和遗忘"的编译器警告
    _ = InitializeAsync();
}

public List<Item> Items 
{ 
    get => _items;
    private set 
    {
        _items = value;
        OnPropertyChanged();
    }
}

// 可以额外添加加载状态和错误信息属性,让视图能反馈状态
public bool IsLoading
{
    get => _isLoading;
    private set
    {
        _isLoading = value;
        OnPropertyChanged();
    }
}

public string? ErrorMessage
{
    get => _errorMessage;
    private set
    {
        _errorMessage = value;
        OnPropertyChanged();
    }
}

private async Task InitializeAsync()
{
    IsLoading = true;
    ErrorMessage = null;
    try
    {
        Items = await _service.GetItemsAsync();
    }
    catch (Exception ex)
    {
        ErrorMessage = $"加载数据失败:{ex.Message}";
        // 这里可以根据需求记录日志或者做其他异常处理
    }
    finally
    {
        IsLoading = false;
    }
}

// 简化属性变更触发的辅助方法
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

这个方案的好处是完全贴合MVVM的设计原则,不需要修改任何视图代码——视图一开始会显示空列表(或者你可以利用新增的IsLoading和ErrorMessage在视图里添加加载动画或错误提示),等数据加载完成后会自动刷新显示内容。

方案二:使用Lazy实现延迟加载(按需加载场景适用)

如果你的需求是第一次访问Items时才触发加载(而不是页面初始化就加载),可以用Lazy<Task>来实现线程安全的延迟异步加载。不过这个方案需要稍微修改视图代码,如果你能接受的话可以试试:

ViewModel代码:

private readonly IItemService _service;
private readonly Lazy<Task<List<Item>>> _lazyItems;

public IndexViewModel(IItemService service)
{
    _service = service;
    _lazyItems = new Lazy<Task<List<Item>>>(FetchItemsAsync);
}

// 把Items改成异步属性
public async Task<List<Item>> Items => await _lazyItems.Value;

private async Task<List<Item>> FetchItemsAsync()
{
    return await _service.GetItemsAsync();
}

视图里的遍历需要改成:

<ul>
  @foreach (var item in await viewmodel.Items) 
  {
     <li>@item.Name</li>
  }
</ul>

关键注意事项

  1. 异常处理不能忘:不管用哪个方案,一定要在异步任务里捕获异常,避免未处理的异常导致应用崩溃。可以像方案一那样添加错误状态属性,给用户清晰的反馈。
  2. 构造函数异步任务的警告:用_ = InitializeAsync();是为了避免编译器的"异步方法缺少等待"警告,但一定要确保任务内部的异常被处理,否则可能会导致应用终止。

备注:内容来源于stack exchange,提问作者BOGsi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:43:06