如何在回调中获取Blazored.TextEditor的HTML文本并解决报错
解决Blazored.TextEditor在MudDialog中调用UpdateBody时的组件销毁错误
问题场景
封装自定义TextEditor组件并嵌入MudDialog对话框内,点击对话框保存按钮触发Submit方法时,调用textEditor.UpdateBody()获取HTML文本抛出错误,推测原因是对话框提前关闭导致组件已被销毁。
错误信息
System.AggregateException: One or more errors occurred. (TypeError: Cannot read properties of null (reading 'removeChild')) ---> System.InvalidOperationException: TypeError: Cannot read properties of null (reading 'removeChild') at Microsoft.AspNetCore.Components.RenderTree.Renderer.InvokeRenderCompletedCallsAfterUpdateDisplayTask(Task updateDisplayTask, Int32[] updatedComponents)
相关代码
对话框代码
<MudDialog> <DialogContent> <MudForm Model="@Model" @ref="@_form" Validation="@(Validator.ValidateValue(Model))"> <MudGrid> <MudItem xs="12"> <MudTextField Label="@L["Name"]" @bind-Value="Model.Name" For="@(() => Model.Name)" Required="true" RequiredError="@L["Name is required!"]"> </MudTextField> </MudItem> <MudItem xs="12"> <TextEditor @ref="textEditor" Body="@Model.Description" BodyChanged="@OnBodyChanged" /> </MudItem> </MudGrid> </MudForm> </DialogContent> <DialogActions> <MudButton OnClick="Cancel">Cancel</MudButton> <MudButton OnClick="Submit">Save</MudLoadingButton> </DialogActions> </MudDialog> @code { [CascadingParameter] private MudDialogInstance MudDialog { get; set; } [EditorRequired] [Parameter] public UpdateItemCommand Model { get; set; } private MudForm? _form; private TextEditor textEditor; private async Task Submit() { await _form!.Validate().ConfigureAwait(false); await textEditor.UpdateBody(); // This line throws an error. if(!_form!.IsValid) { return; } var result = await Mediator.Send(Model); if(result.Succeeded) { MudDialog.Close(DialogResult.Ok(true)); Notify(result.SuccessMessage); } else { Notify(result.ErrorMessage); } } private void Cancel() { MudDialog.Cancel(); } private void OnBodyChanged(string body) { Model.Description = body; } }
自定义TextEditor组件代码
<BlazoredTextEditor @ref="@Editor"> <ToolbarContent> <span class="ql-formats"> <select class="ql-font"> <option selected=""></option> <option value="serif"></option> <option value="monospace"></option> </select> <select class="ql-size"> <option value="small"></option> <option selected=""></option> <option value="large"></option> <option value="huge"></option> </select> </span> <span class="ql-formats"> <button class="ql-bold"></button> <button class="ql-italic"></button> <button class="ql-underline"></button> <button class="ql-strike"></button> </span> <span class="ql-formats"> <select class="ql-color"></select> <select class="ql-background"></select> </span> <span class="ql-formats"> <button class="ql-list" value="ordered"></button> <button class="ql-list" value="bullet"></button> <button class="ql-indent" value="-1"></button> <button class="ql-indent" value="+1"></button> <select class="ql-align"> <option selected=""></option> <option value="center"></option> <option value="right"></option> <option value="justify"></option> </select> </span> <span class="ql-formats"> <button class="ql-link"></button> </span> </ToolbarContent> <EditorContent> @((MarkupString)Body) </EditorContent> </BlazoredTextEditor> @code { BlazoredTextEditor Editor; [Parameter] public string Body { get; set; } = string.Empty; [Parameter] public EventCallback<string> BodyChanged { get; set; } public async Task UpdateBody() { Body = await Editor.GetHTML(); await BodyChanged.InvokeAsync(Body); } }
解决方案
1. 调整异步操作顺序与线程上下文
原代码中使用.ConfigureAwait(false)会脱离UI线程,可能导致组件状态更新与销毁的时序问题。修改Submit方法,确保所有操作在UI线程完成,且先完成编辑器内容获取再处理后续逻辑:
private async Task Submit() { // 先执行表单验证,确保在UI线程处理 await _form!.Validate(); if (!_form!.IsValid) { return; } // 确保编辑器内容获取完成后再发送请求 await textEditor.UpdateBody(); var result = await Mediator.Send(Model); if (result.Succeeded) { // 所有异步操作完成后再关闭对话框 MudDialog.Close(DialogResult.Ok(true)); Notify(result.SuccessMessage); } else { Notify(result.ErrorMessage); } }
2. 在TextEditor组件中添加空值防护
在自定义TextEditor的UpdateBody方法中增加Editor实例的空值检查,避免调用已销毁组件的方法:
public async Task UpdateBody() { if (Editor == null) { return; } Body = await Editor.GetHTML(); await BodyChanged.InvokeAsync(Body); }
3. 延迟对话框关闭(可选)
如果仍存在时序问题,可以在确认操作成功后延迟关闭对话框,确保UI状态更新完成:
private async Task Submit() { await _form!.Validate(); if (!_form!.IsValid) { return; } await textEditor.UpdateBody(); var result = await Mediator.Send(Model); if (result.Succeeded) { Notify(result.SuccessMessage); // 延迟100ms确保UI更新完成后再关闭 await Task.Delay(100); MudDialog.Close(DialogResult.Ok(true)); } else { Notify(result.ErrorMessage); } }
内容的提问来源于stack exchange,提问作者Sachihiro
相关产品推荐
相关产品推荐

