Blazor Server中Bootstrap OffCanvas内TelerikPDFViewer内容不刷新问题
问题描述
在Blazor Server项目中,我将Telerik PDFViewer控件嵌套在Blazor Bootstrap的OffCanvas控件内。点击表格行内按钮需完成以下操作:
- 获取当前行的条目ID,调用方法获取生成PDF的数据
- 将PDF数据赋值给绑定到Telerik PDFViewer的对象
- 调用OffCanvas的
ShowAsync()方法显示面板以展示PDF
遇到的异常情况:使用await调用ShowAsync()时,PDF内容无法刷新;移除await关键字后则能正常刷新。首次调用PDF显示正常,但点击其他行按钮时PDF内容保持不变,去掉await后每次点击都能正确加载对应行的PDF。
触发按钮的处理方法代码如下:
private async Task ViewTOPCasePDFHandler(GridCommandEventArgs args) { TOPCase item = args.Item as TOPCase; // 获取点击了「查看PDF」按钮的行数据 string pdfBase64String = await _topService.GenerateFormCompletedPDF(item.CaseID); // 调用方法获取PDF内容 pdfViewerModel = new PdfViewerModel() // 将PDF内容赋值给绑定到Telerik PDFViewer的模型 { PdfSource = Convert.FromBase64String(pdfBase64String), DownloadFilename = Convert.ToDateTime(item.CreatedDate).ToString("yyyy_MM_dd") + "_MyForm_" + item.CaseID.ToString() }; await pdfViewerWindow.ShowAsync(); // 显示OffCanvas面板 }
原因分析
这是Blazor Server的组件渲染时机与异步操作顺序冲突导致的:
- 使用
await ShowAsync()时,该异步方法会优先触发OffCanvas的UI更新,此时Blazor的渲染上下文尚未完成pdfViewerModel的状态变更同步,导致PDFViewer读取的仍是旧模型数据。 - 移除
await后,ShowAsync()会作为“火并忘”的异步操作执行,此时pdfViewerModel的赋值先完成,状态变更通知Blazor触发重新渲染,之后OffCanvas才显示,PDFViewer能获取到最新的模型数据。
但直接去掉await可能引发潜在的异步异常问题,更稳妥的做法是确保状态更新先被Blazor捕获,再触发面板显示。
解决方案
推荐以下两种可靠的解决方式:
- 强制触发状态更新后再显示面板
在赋值pdfViewerModel后,调用StateHasChanged()通知Blazor立即同步状态,再执行面板显示操作:
private async Task ViewTOPCasePDFHandler(GridCommandEventArgs args) { TOPCase item = args.Item as TOPCase; string pdfBase64String = await _topService.GenerateFormCompletedPDF(item.CaseID); pdfViewerModel = new PdfViewerModel() { PdfSource = Convert.FromBase64String(pdfBase64String), DownloadFilename = Convert.ToDateTime(item.CreatedDate).ToString("yyyy_MM_dd") + "_MyForm_" + item.CaseID.ToString() }; StateHasChanged(); // 强制通知Blazor更新状态 await Task.Delay(1); // 给渲染流程预留极短时间(可选,视实际情况调整) await pdfViewerWindow.ShowAsync(); }
- 使用
InvokeAsync包裹状态更新与显示逻辑
利用Blazor的InvokeAsync确保所有操作在正确的渲染上下文中执行:
private async Task ViewTOPCasePDFHandler(GridCommandEventArgs args) { TOPCase item = args.Item as TOPCase; string pdfBase64String = await _topService.GenerateFormCompletedPDF(item.CaseID); await InvokeAsync(() => { pdfViewerModel = new PdfViewerModel() { PdfSource = Convert.FromBase64String(pdfBase64String), DownloadFilename = Convert.ToDateTime(item.CreatedDate).ToString("yyyy_MM_dd") + "_MyForm_" + item.CaseID.ToString() }; return pdfViewerWindow.ShowAsync(); }); }
内容的提问来源于stack exchange,提问作者gib_stu01
相关产品推荐
相关产品推荐

