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

Blazor调用StateHasChanged后UI未自动更新问题求助

Blazor UI自动更新失效问题解决方案

核心问题分析

你的代码中虽然调用了InvokeAsync(StateHasChanged),但Blazor组件无法自动感知LifetimeService.Items集合的内容变化——List<T>本身不具备变更通知能力,且组件没有绑定集合的变更事件,导致UI无法同步更新。

解决步骤及代码修改

1. 改造LifetimeService,添加集合变更通知

将List<Item>替换为ObservableCollection<Item>(自带集合变更事件),或者保留List但自定义变更事件。这里推荐前者,更符合Blazor的响应式设计:

using System.Collections.ObjectModel;

public class LifetimeService
{
    public int ScanAmounts = 0;

    // 使用ObservableCollection替代List,支持自动变更通知
    public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();

    public bool AddItem(Item item)
    {           
        if (Items.Any(x => x.Name == item.Name && x.Price == item.Price && x.Image == item.Image && x.Link == item.Link))
        {
            return false;
        }
        
        if (ScanAmounts == 0)
        {
            Items.Add(item);
        }
        else
        {
            Items.Insert(0, item);
        }
        return true;
    }
}

2. 组件中订阅集合变更事件,自动触发UI更新

在组件中订阅ObservableCollection的CollectionChanged事件,确保集合内容变化时自动调用StateHasChanged:

@implements IDisposable

<!-- 原表格代码保持不变 -->
<table class="table">
    <thead>
        <tr>
            <th>Image</th>
            <th>Name</th>
            <th>Price</th>
            <th>Link</th>
            <th>ItemSlot</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in LifetimeService.Items)
        {
            <tr>
                <td><img src="@item.Image" alt="Image" width="100" height="100" /></td>
                <td>@item.Name</td>
                <td>@item.Price</td>
                <td><a href="@item.Link">Link</a></td>
            </tr>
        }
    </tbody>
</table>

@code {
    [Inject]
    public LifetimeService LifetimeService { get; set; } = default!;

    private Timer? _timer;
    private IDisposable? _collectionSubscription;

    protected override async Task OnParametersSetAsync()
    {
        await base.OnParametersSetAsync();  
        
        if (LifetimeService.Items.Count > 0)
        {
            return;
        }
        StartTimer();
        await ScrapeData();
    }

    protected override void OnInitialized()
    {
        base.OnInitialized();
        // 订阅集合变更事件,自动触发UI更新
        _collectionSubscription = LifetimeService.Items.CollectionChanged += (s, e) => InvokeAsync(StateHasChanged);
    }

    private void StartTimer()
    {
        _timer = new Timer(async _ =>
           {
               await InvokeAsync(ScrapeData);
           }, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
    }

    // 原ScrapeData方法保持不变
    private async Task ScrapeData()
    {
        // ...你的爬虫逻辑...
    }

    // 清理资源,避免内存泄漏
    public void Dispose()
    {
        _timer?.Dispose();
        _collectionSubscription?.Dispose();
    }
}

3. 额外检查项

  • 确保LifetimeService在Program.cs中正确注册(根据业务场景选择Scoped或Singleton):
    // 单用户场景用Scoped,多用户共享数据用Singleton
    builder.Services.AddScoped<LifetimeService>();
    
  • 如果使用Singleton服务,为保证线程安全,在AddItem方法中添加锁:
    lock (Items)
    {
        if (ScanAmounts == 0)
        {
            Items.Add(item);
        }
        else
        {
            Items.Insert(0, item);
        }
    }
    
  • 确认Item类的属性均为公开可访问,Blazor只能绑定公开属性。

内容的提问来源于stack exchange,提问作者D74

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:05:03