MudDialog写入XML时进度对话框无法实时弹出问题排查
问题:进度对话框在任务完成后才显示,而非处理过程中
我创建了一个包含MudProgressCircular的自定义对话框组件(Child.razor),原本应该在将零件详情写入XML输出文件时显示进度,但实际问题是对话框不会在保存文件的过程中打开,而是要等整个任务完成后才弹出。
Parent.razor
<MudButton Class="mt-2" OnClick="@(() => OnClickedAsync())" Color="Color.Primary" Size="Size.Small" Edge="Edge.Start">Process Parts</MudButton> @code { private List<Part> partItems; private async Task OnClickedAsync() { using (var handler = new HttpClientHandler()) { using (var httpClient = new HttpClient(handler)) { serviceEndpoint = $"{Config.GetValue<string>("API")}/Parts"; var parts = await httpClient.GetFromJsonAsync<Part[]>(serviceEndpoint); partItems = parts.ToList(); } } ProcessParts(partItems); } private void ProcessParts(List<Part> parts) { var options = new DialogOptions { FullWidth = true, MaxWidth = MaxWidth.ExtraExtraLarge, CloseButton = true, Position = DialogPosition.Center, CloseOnEscapeKey = true }; var param = new DialogParameters(); param.Add("Parts", parts); var dialogRef = Dialogsrv.Show<Child>($"Processing parts", param, options); }
Child.razor
<MudDialog Style="width:fit-content"> <DialogContent> <MudProgressCircular Color="Color.Primary" Value="@_value" Size="Size.Large"> @_value.ToString("N0") % </MudProgressCircular> </DialogContent> <DialogActions> <MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Close">Close</MudButton> </DialogActions> </MudDialog> @code { [CascadingParameter] private IMudDialogInstance ThisDialog { get; set; } [Parameter] public List<Part> Parts { get; set; } private int count = 0; private double _value; protected override void OnInitialized() { ProcessParts(Parts); } private void ProcessParts(List<Part> parts) { XDocument doc = XDocument.Load("Contents\\Template.xml"); XElement root = doc.Root; foreach (var part in parts) { root.Element("Parts").Add( new XElement("Part", new XElement("PartNo", part.Part), new XElement("Filename", part.FileName), new XElement("Material", part.Material), new XElement("CustomerName", part.CustomerName) )); count++; _value = 100 * count / parts.Count; } string fullPath = Path.Combine(_filePath, "Parts.xml"); using (StreamWriter stream = new StreamWriter(fullPath, false, Encoding.GetEncoding("Windows-1252"))) { doc.Save(stream); } } }
已确认事项
- MainLayout.razor中已存在
MudDialogProvider - 对话框服务已在依赖注入中注册
我曾以为是async/await问题,把Child.razor中的方法改成了同步,但问题依然存在。
解决方案
问题核心是同步耗时操作阻塞了Blazor的UI线程,导致对话框无法及时渲染,进度更新也无法实时显示。Blazor的UI更新依赖于同步上下文,长时间的同步任务会占据线程,直到任务结束才会处理UI渲染请求。
修改Child.razor的关键步骤:
- 将初始化方法改为异步的
OnInitializedAsync,避免阻塞组件初始化流程 - 将耗时的
ProcessParts操作放到后台线程执行(用Task.Run) - 在进度更新后,调用
InvokeAsync(StateHasChanged)通知UI更新
修改后的Child.razor代码:
<MudDialog Style="width:fit-content"> <DialogContent> <MudProgressCircular Color="Color.Primary" Value="@_value" Size="Size.Large"> @_value.ToString("N0") % </MudProgressCircular> </DialogContent> <DialogActions> <MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Close" Disabled="@_isProcessing">Close</MudButton> </DialogActions> </MudDialog> @code { [CascadingParameter] private IMudDialogInstance ThisDialog { get; set; } [Parameter] public List<Part> Parts { get; set; } private int count = 0; private double _value; private bool _isProcessing; protected override async Task OnInitializedAsync() { _isProcessing = true; // 将耗时操作放到后台线程,避免阻塞UI await Task.Run(() => ProcessParts(Parts)); _isProcessing = false; // 任务完成后可选择自动关闭对话框,或保留让用户手动关闭 // ThisDialog.Close(DialogResult.Ok(true)); } private void ProcessParts(List<Part> parts) { XDocument doc = XDocument.Load("Contents\\Template.xml"); XElement root = doc.Root; foreach (var part in parts) { root.Element("Parts").Add( new XElement("Part", new XElement("PartNo", part.Part), new XElement("Filename", part.FileName), new XElement("Material", part.Material), new XElement("CustomerName", part.CustomerName) )); count++; _value = 100 * (double)count / parts.Count; // 通知UI更新进度 InvokeAsync(StateHasChanged); // 可选:模拟慢进度用于测试 // Thread.Sleep(50); } string fullPath = Path.Combine(_filePath, "Parts.xml"); using (StreamWriter stream = new StreamWriter(fullPath, false, Encoding.GetEncoding("Windows-1252"))) { doc.Save(stream); } } private void Close() => ThisDialog.Close(DialogResult.Cancel()); }
额外说明:
- 使用
Task.Run将IO/CPU密集型操作移到后台线程,释放UI线程处理渲染和用户交互 InvokeAsync(StateHasChanged)确保进度更新能触发UI重新渲染(后台线程无法直接更新Blazor UI)- 添加
_isProcessing变量禁用Close按钮,避免用户在任务未完成时关闭对话框 - 修正路径转义符:原代码中
"Contents\Template.xml"会被解析为转义字符,改为"Contents\\Template.xml"避免文件找不到问题
内容的提问来源于stack exchange,提问作者JHWPG
相关产品推荐
相关产品推荐

