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

Blazor模板值未更新问题:自定义网格复选框状态不同步

问题描述

我正在开发一个自定义网格组件,每行包含一个复选框,复选框状态决定行的CSS类。但当复选框状态改变时,Test.razor中显示的row.Checked值始终不更新——即使调试时该值实际是正确的,界面上一直显示false。相关代码如下:

Index.razor

<Test Items="Transactions">
    <TestBody Context="row">
        <TestCell Row=row></TestCell>
    </TestBody>
</Test>

Test.razor

@typeparam TItem

@attribute [CascadingTypeParameter(nameof(TItem))];

<CascadingValue Value="this" IsFixed="true">
    <table>
        <tbody>
            @foreach (var row in Rows)
            {
                <tr @key="row">
                    @TestBody(row)
                    <span>@row.Checked</span>   // .. this does not get updated
                </tr>
            }
        </tbody>
    </table>
</CascadingValue>

Test.razor.cs

namespace Accounting.Web.Components.Test
{
    public class TestRow<TItem>
    {
        public TItem Item { get; set; } = default!;
        public int Id { get; set; } = default!;
        public bool Checked = false;
    }

    public partial class Test<TItem>
    {
        [Parameter]
        public IList<TItem> Items { get; set; } = default!;

        [Parameter]
        public RenderFragment<TestRow<TItem>> TestBody { get; set; } = default!;

        public List<TestRow<TItem>> Rows { get; set; } = new();

        protected override void OnInitialized()
        {
            int i = 1;
            foreach (var item in Items)
            {
                var gridRow = new TestRow<TItem>()
                {
                    Id = i,
                    Item = item,
                };
                Rows.Add(gridRow);
                i++;
            }
        }
    }
}

TestCell.razor

@typeparam TItem

<input type="checkbox" @onchange="eventArgs => { OnCheckChanged(eventArgs.Value); }" />

TestCell.razor.cs

namespace Accounting.Web.Components.Test
{
    public partial class TestCell<TItem>
    {
        [Parameter]
        public TestRow<TItem> Row { get; set; } = default!;

        [Parameter]
        public RenderFragment ChildContent { get; set; } = default!;

        public void OnCheckChanged(object checkedValue)
        {
            System.Console.WriteLine((bool)checkedValue); // this reflects the correct state of the checkbox
            Row.Checked = (bool)checkedValue;
            StateHasChanged();
        }
    }
}
问题原因与修复方案

1. TestRow中的Checked是字段而非属性

Blazor的UI更新依赖属性变更通知机制,但你定义的Checked是字段(public bool Checked = false;),不是带get/set的属性。Blazor无法检测到字段的变化,因此Test.razor的UI不会更新。

修复:将Checked改为属性:

public class TestRow<TItem>
{
    public TItem Item { get; set; } = default!;
    public int Id { get; set; } = default!;
    public bool Checked { get; set; } = false; // 改为属性
}

2. 仅在TestCell中调用StateHasChanged()无效

TestCell的状态更新只会刷新自身组件,不会通知父组件Test。必须触发Test组件的状态更新,才能让它重新渲染并显示最新的Checked值,有两种方案可选:

方案一:通过事件通知父组件

在TestCell中定义事件,复选框状态改变时触发事件,让Test组件接收并更新自身状态:
修改TestCell.razor.cs:

public partial class TestCell<TItem>
{
    [Parameter]
    public TestRow<TItem> Row { get; set; } = default!;

    [Parameter]
    public RenderFragment ChildContent { get; set; } = default!;

    [Parameter]
    public EventCallback OnCheckedChanged { get; set; } // 新增事件

    public void OnCheckChanged(object checkedValue)
    {
        Row.Checked = (bool)checkedValue;
        OnCheckedChanged.InvokeAsync(); // 触发事件通知父组件
        StateHasChanged();
    }
}

在Index.razor中绑定事件到Test组件的状态更新方法:

<Test Items="Transactions" @ref="testComponent">
    <TestBody Context="row">
        <TestCell Row=row OnCheckedChanged="() => testComponent.StateHasChanged()"></TestCell>
    </TestBody>
</Test>

@code {
    private Test<TransactionType>? testComponent; // 替换TransactionType为你的实际数据类型
}

方案二:让TestRow实现INotifyPropertyChanged

通过实现接口来主动通知属性变更,Blazor会自动监听并更新UI:
修改TestRow:

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

public class TestRow<TItem> : INotifyPropertyChanged
{
    public TItem Item { get; set; } = default!;
    public int Id { get; set; } = default!;

    private bool _checked;
    public bool Checked
    {
        get => _checked;
        set
        {
            if (_checked != value)
            {
                _checked = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

这种方式无需手动调用StateHasChanged(),Blazor会自动处理UI更新。

3. 额外优化:复选框双向绑定

当前复选框未与Row.Checked双向绑定,初始状态不会同步Row.Checked的值。建议改为双向绑定简化代码:

<input type="checkbox" @bind="Row.Checked" @bind:event="onchange" />

这样可以直接删除OnCheckChanged方法,同时保证复选框状态与Row.Checked始终一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:20:23