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

如何用服务实现组件间数据共享?ChildContent配置遇空集合问题

问题根源

你的问题出在Blazor的组件渲染顺序上:Table组件会先渲染自身的UI(也就是遍历Headers的循环),之后才会渲染ChildContent里的Header组件。这就导致Table第一次渲染时,Header组件还没执行OnParametersSet方法往TableService的集合里添加数据,所以你看到的是空集合。

下面给出几个针对性的解决方案:

方案一:用ObservableCollection实现自动更新

把TableService里的List<Header>换成ObservableCollection<Header>,并通过事件通知组件数据变化,触发重新渲染。

修改TableService.cs

using System.Collections.ObjectModel;
using System.Collections.Specialized;

public class TableService
{
    // 换成ObservableCollection,支持集合变化通知
    public ObservableCollection<Header> Headers { get; } = new();

    public TableService()
    {
        // 监听集合变化,触发自定义事件
        Headers.CollectionChanged += (sender, e) => OnHeadersChanged?.Invoke();
    }

    // 用于通知组件更新的事件
    public event Action? OnHeadersChanged;
}

修改Table.razor

@inject TableService TableService
@implements IDisposable

@foreach (var header in TableService.Headers)
{
    <span>@header.Name</span>
}

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; } 

    protected override void OnInitialized()
    {
        // 订阅集合变化事件,触发组件重新渲染
        TableService.OnHeadersChanged += StateHasChanged;
    }

    // 组件销毁时取消订阅,避免内存泄漏
    public void Dispose()
    {
        TableService.OnHeadersChanged -= StateHasChanged;
    }
}

当Header组件往集合里添加数据时,TableService会触发事件,Table组件收到后自动重新渲染,就能显示最新的Headers了。

方案二:调整Table组件的渲染时机

先渲染ChildContent里的Header组件,等第一次渲染完成后,再显示Table的UI。

修改Table.razor

@inject TableService TableService

@* 等待ChildContent渲染完成后再显示Headers *@
@if (_isChildContentRendered)
{
    @foreach (var header in TableService.Headers)
    {
        <span>@header.Name</span>
    }
}

@* 先渲染ChildContent里的Header组件 *@
@ChildContent

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; } 
    private bool _isChildContentRendered;

    protected override async Task AfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 标记ChildContent已渲染,触发组件重新渲染
            _isChildContentRendered = true;
            await InvokeAsync(StateHasChanged);
        }
    }
}

这个方案利用AfterRenderAsync生命周期方法,在第一次渲染完成后(此时Header已经往服务里加了数据),再显示Table的Headers内容。

方案三:直接通过组件树传递数据(无需服务)

如果只是Table和它的子Header组件之间共享数据,没必要用服务,直接通过级联参数+方法调用的方式更简单,还能避免渲染顺序问题。

修改Table.razor

@foreach (var header in _headers)
{
    <span>@header.Name</span>
}

@ChildContent

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; } 
    private List<Header> _headers = new();

    // 提供给Header组件调用的添加方法
    public void AddHeader(Header header)
    {
        _headers.Add(header);
        StateHasChanged();
    }
}

修改Header.razor

@code {
    [Parameter] public string? Name { get; set; }
    // 通过级联参数获取父级Table组件
    [CascadingParameter] public Table? ParentTable { get; set; }

    protected override void OnParametersSet()
    {
        // 调用父组件的方法添加Header
        ParentTable?.AddHeader(new Header { Name = this.Name });
    }
}

这种方式直接在组件树内部完成数据传递,不需要依赖服务,逻辑更清晰,也不会有渲染顺序的问题。

额外提示

你的Index.razor里有个语法错误:<Header Name="Email/>少了闭合引号,应该改成<Header Name="Email"/>。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 05:17:03