如何用服务实现组件间数据共享?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
相关产品推荐
相关产品推荐

