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

WPF C# 计算磁盘文件时如何避免UI冻结?

问题分析与解决方案

你的UI冻结问题核心原因是把耗时的磁盘计算逻辑丢回了UI线程执行:原代码中DirSize这个最耗时的方法被包裹在Dispatcher.Invoke内部,等于让UI线程去执行文件大小统计,自然会导致窗口无法响应。

修正步骤

1. 完善目录大小计算方法(递归处理子目录)

先补全DirSize的递归逻辑,同时确保它只做计算,不碰任何UI元素:

public static long DirSize(DirectoryInfo d)
{
    long size = 0;
    // 统计当前目录下的文件
    FileInfo[] fis = d.GetFiles();
    foreach (FileInfo fi in fis)
    {
        try
        {
            size += fi.Length;
        }
        catch
        {
            // 跳过无权限或无法访问的文件
        }
    }
    // 递归统计子目录
    DirectoryInfo[] subDirs = d.GetDirectories();
    foreach (DirectoryInfo subDir in subDirs)
    {
        try
        {
            size += DirSize(subDir);
        }
        catch
        {
            // 跳过无权限或无法访问的子目录
        }
    }
    return size;
}

2. 修正异步事件逻辑

将耗时计算放在后台线程执行,await完成后自动回到UI线程更新控件,无需手动调用Dispatcher.Invoke:

private async void Save_bkp_Click(object sender, RoutedEventArgs e)
{
    // 把耗时计算交给后台线程
    long totalSize = await Task.Run(() => DirSize(new DirectoryInfo(CopiaFoto)));
    // await后自动切回UI线程,直接更新文本框
    TextBox_Dimensioni.Text = Convert.ToString((double)totalSize);
}

关键说明

  • Task.Run负责将DirSize放到后台线程执行,此时UI线程完全空闲,窗口可以正常拖动、响应操作。
  • await关键字会等待后台任务完成,之后自动切换回UI线程上下文,所以更新控件时不会触发跨线程访问错误,无需额外的Dispatcher.Invoke。
  • 原代码的错误在于:把最耗时的计算逻辑包裹在Dispatcher.Invoke中,等于强制让UI线程去做磁盘统计,完全违背了异步的初衷。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:47:11