Blazor循环组件中InputFile的OnChange事件无法识别所属组件问题
问题分析与解决方案
问题根源
- 循环组件未指定
@key:Blazor在循环渲染组件时,若未提供唯一@key,会复用组件实例,导致事件绑定的上下文混乱,所有上传事件都指向第一个组件实例。 - InputFile的ID重复:所有
InputFile和对应label使用固定IDinputGroupFile,点击任意按钮都会触发第一个匹配的InputFile。 - 事件回调参数传递错误:原代码中
EventCallback未正确携带组件ID,且参数解构写法错误,导致无法匹配目标组件。
分步修复
1. 顶级页面:给循环组件添加@key
@page "/testing" @foreach (var id in testingRepeaterIds) { <TestingRepeater ComponentId="id" @key="id"></TestingRepeater> } @code { private List<int> testingRepeaterIds = new List<int> { 1, 2, 3 }; }
- 作用:让Blazor精准跟踪每个
TestingRepeater实例,避免复用导致的上下文混乱。
2. TestUpload组件:修复ID重复与回调参数
<div class="custom-file"> <InputFile @key=@(_inputFileId) OnChange=@LoadFiles accept="image/png, image/jpg, image/jpeg" style="width: 0px;" multiple class="custom-file-input d-none" id="@_inputFileId" /> <label class="rz-button rz-button-md rz-variant-flat rz-dark rz-shade-dark" for="@_inputFileId">Choose File(s)</label> </div> @code { [Parameter] public EventCallback<(List<AttachmentDto> Files, int EntityId)> OnChange { get; set; } [Parameter] public int EntityId { get; set; } private List<AttachmentDto> loadedFiles = new(); private bool isLoading; private string _inputFileId = Guid.NewGuid().ToString(); private async Task LoadFiles(InputFileChangeEventArgs e) { isLoading = true; loadedFiles.Clear(); // 清空历史文件,避免重复添加 foreach (var file in e.GetMultipleFiles()) { var uploadedFile = new AttachmentDto { DiskName = Path.Combine("uploads", file.Name), FileName = file.Name, FileSize = file.Size, FileType = file.ContentType, }; loadedFiles.Add(uploadedFile); } await OnChange.InvokeAsync((loadedFiles, EntityId)); isLoading = false; } }
- 动态生成
InputFile的ID并绑定到label,解决ID重复问题。 - 修改
EventCallback为元组类型,同时传递文件列表与组件ID,确保回调能匹配目标组件。 - 每次上传前清空文件列表,避免重复添加历史文件。
3. TestingRepeater组件:修正回调逻辑
<TestUpload OnChange="@((args) => LinkFilesToComponent(args.Files, args.EntityId))" EntityId="@ComponentId" /> <RadzenDataGrid @ref="attachmentGrid" AllowSorting="true" PagerHorizontalAlign="HorizontalAlign.Left" ColumnWidth="140px" Data="@attachedFiles" TItem="AttachmentDto" LogicalFilterOperator="LogicalFilterOperator.Or" Responsive="true"> <Columns> <RadzenDataGridColumn TItem="AttachmentDto" Property="FileName" Title="Name"> <Template Context="attachment"> <RadzenTextBox @bind-Value="attachment.FileName" class="w-100" /> </Template> </RadzenDataGridColumn> </Columns> </RadzenDataGrid> @code { [Parameter] public int ComponentId { get; set; } private RadzenDataGrid<AttachmentDto> attachmentGrid; private List<AttachmentDto> attachedFiles = new List<AttachmentDto>(); private async Task LinkFilesToComponent(List<AttachmentDto> files, int entityId) { if (entityId == ComponentId) { attachedFiles.AddRange(files); await attachmentGrid.ReloadAsync(); // 使用异步重载方法,符合Blazor异步规范 } } }
- 修正回调参数的解构方式,正确接收文件列表与组件ID。
- 将
async void改为async Task,避免异步操作潜在的异常问题。 - 使用
AddRange替代循环Add,简化代码逻辑。
4. AttachmentDto:修正无效特性
public class AttachmentDto { [MaxLength(1000)] public string FileName { get; set; } [MaxLength(1000)] public string FileType { get; set; } public long FileSize { get; set; } // 移除无效的MaxLength特性 [MaxLength(1000)] public string DiskName { get; set; } }
MaxLength特性对long类型无效,直接移除。
内容的提问来源于stack exchange,提问作者Hannah Hayes
相关产品推荐
相关产品推荐

