You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server(.NET 9)批量处理图片时动态渲染仅在结束时生效问题

问题:Blazor Server批量处理图片时无法逐张实时预览

我基于.NET 9开发了Blazor Server应用,已在Program.cs中启用Interactive Server渲染模式:

app.MapRazorComponents<App>()
   .AddInteractiveServerRenderMode(); 

文件上传进度条功能正常,但批量处理图片时出现问题:本该每处理完一张就向用户展示预览图,实际却要等所有图片处理完成后才统一刷新UI。

图片处理逻辑代码:

private async Task ProcessImages()
{
    Bitmap processedimage = null;
    foreach (var file in selectedFiles)
    {
        using (var img = Bitmap.FromFile(file))
        {
            processedimage = imageservice.Process((Bitmap)img);
            using (var ms = new MemoryStream())
            {
                using (var bitmap = new Bitmap(processedimage ))
                {
                    bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                    ImageUri = $"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}";
                    StateHasChanged();
                }
            }
        }
    }
}

图片展示的HTML代码:

<img src=@ImageUri asp-append-version="true" width="190px" style="float: none; text-align: left; border-radius: 10px; border: 2px dotted #0332ff; padding: 40px" />

问题原因

  1. 虽然ProcessImages标记为async,但内部没有真正的异步等待操作,本质是同步执行的长任务,会持续占用UI线程,导致Blazor无法及时推送UI更新。
  2. StateHasChanged()仅标记组件需要重新渲染,但在同步任务阻塞期间,渲染请求会被积压,直到整个任务完成后才一次性执行。

解决方案

方案1:插入异步等待释放UI线程

在每次处理完一张图片后,通过await Task.Yield()让UI线程有机会处理渲染更新:

private async Task ProcessImages()
{
    Bitmap processedimage = null;
    foreach (var file in selectedFiles)
    {
        using (var img = Bitmap.FromFile(file))
        {
            processedimage = imageservice.Process((Bitmap)img);
            using (var ms = new MemoryStream())
            {
                using (var bitmap = new Bitmap(processedimage))
                {
                    bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                    ImageUri = $"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}";
                    StateHasChanged();
                    // 释放UI线程处理渲染
                    await Task.Yield();
                }
            }
        }
    }
}

方案2:将图片处理移到后台线程

如果图片处理耗时较长,建议把处理逻辑放到后台线程,彻底避免阻塞UI:

private async Task ProcessImages()
{
    foreach (var file in selectedFiles)
    {
        // 后台线程执行图片处理
        var processedImage = await Task.Run(() =>
        {
            using (var img = Bitmap.FromFile(file))
            {
                return imageservice.Process((Bitmap)img);
            }
        });

        using (var ms = new MemoryStream())
        {
            using (var bitmap = new Bitmap(processedImage))
            {
                bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                // 确保在UI线程更新状态
                await InvokeAsync(() =>
                {
                    ImageUri = $"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}";
                    StateHasChanged();
                });
                await Task.Yield();
            }
        }
    }
}

额外优化建议

如果需要展示所有已处理的图片,不要用单个ImageUri覆盖,改用列表存储每张图片的Base64地址,再通过循环渲染多张图片:

// 定义列表存储所有处理后的图片Uri
private List<string> ProcessedImageUris = new();

// 修改处理逻辑
await InvokeAsync(() =>
{
    ProcessedImageUris.Add($"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}");
    StateHasChanged();
});

渲染部分:

@foreach (var uri in ProcessedImageUris)
{
    <img src=@uri asp-append-version="true" width="190px" style="float: none; text-align: left; border-radius: 10px; border: 2px dotted #0332ff; padding: 40px; margin: 10px;" />
}

内容的提问来源于stack exchange,提问作者techno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 03:05:02