使用Blazor Virtualize组件虚拟化时如何保留行组件编辑状态
问题根因
你遇到的是Blazor Virtualize组件的固有特性:该组件仅渲染可视区域内的元素,滚动出可视区的DOM和对应子组件实例会被直接销毁,滚动回来时会根据数据源重新创建组件实例,所以存储在TableRow子组件内部的局部状态(编辑开关、未保存输入内容)自然会丢失。
核心解决思路:不要将临时状态存储在TableRow子组件的局部变量中,将状态上移到不会被虚拟化销毁的上层,和行数据绑定存储。
具体实现方案
方案1:在原员工模型中扩展临时状态字段(最简便)
给你的Employee实体类新增临时状态字段,可加序列化忽略标记避免提交到后端:
public class Employee { // 原有字段 public Guid EmployeeId { get; set; } public string Name { get; set; } // ... 其他原有字段 // 新增临时状态字段 [JsonIgnore] public bool IsEditing { get; set; } [JsonIgnore] public Employee TempEditData { get; set; } }
子组件直接绑定行数据上的状态,不再自己维护局部状态:
<!--TableRow 子组件修改后--> @if(rowModel.IsEditing) { <tr> <td><input @bind="@rowModel.TempEditData.Name" /></td> <td>...</td> <td><button @onclick="SaveData">保存</button></td> </tr> } else { <tr> <td>@rowModel.Name</td> <td>...</td> <td><button @onclick="EnableEditing">编辑</button></td> </tr> } @code { [Parameter] public Employee rowModel { get; set; } void EnableEditing() { // 初始化临时编辑副本 rowModel.TempEditData = new Employee() { Name = rowModel.Name, // 其他字段复制 }; rowModel.IsEditing = true; } void SaveData() { // 把临时数据覆盖到原数据 rowModel.Name = rowModel.TempEditData.Name; // 其他字段覆盖 rowModel.IsEditing = false; rowModel.TempEditData = null; } }
方案2:父组件单独维护临时状态字典(不改原有模型)
如果不想侵入原有Employee模型,可在父组件单独维护状态存储:
// 父组件代码 public Dictionary<Guid, RowTempState> _editStateDict = new(); public class RowTempState { public bool IsEditing { get; set; } public string TempName { get; set; } // 其他需要临时存储的编辑字段 }
父组件传值给子组件时,额外传入对应行的状态,同时给子组件加@key避免状态错位:
<!--Parent Component 修改后--> <table> <thead>[...]</thead> <tbody> <Virtualize Items="employeeData"> <TableRow @key="context.EmployeeId" rowModel="context" EditState="_editStateDict.TryGetValue(context.EmployeeId, out var state) ? state : new()" /> </Virtualize> </tbody> </table>
子组件的状态都绑定到传入的EditState对象即可。
额外优化提示
如果你的业务只允许同时存在一个编辑行,不需要维护字典,父组件直接存Guid? _editingEmployeeId和对应的临时编辑对象即可,子组件只需要判断当前行ID是否等于_editingEmployeeId即可切换编辑状态。
内容的提问来源于stack exchange,提问作者UnusualWays
相关产品推荐
相关产品推荐

