winforms 跨线程具有IProgress委托的ProgressBar< T>不更新

5rgfhyps  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(138)

我试图在WinForms ProgressBar上显示解压缩几个文件的进度。
在这里,我创建了一个System.Progress,它带有一个更新ProgressBar的处理程序

Progress<int> progress = new Progress<int>(value => {
    progressBar1.Value = value; progressBar1.Update(); });

然后将函数移交给线程池。

Task t = Task.Run(() => FileUtils.UnzipTo(targetDir,
sourceDir, false, progress));

t.Wait();

在我的解压函数中,我对归档中的每个文件都这样做:

progress.Report(++complete / total * 100);

这是明确调用,如果我使用一个方法为我的处理程序,断点是命中每个文件(虽然太晚了,我认为)
我希望这能更新ProgressBar。
我看到对话框,直到文件完全解压缩,上面有一个忙碌的光标,但没有增加进度。
我错过了什么?

e3bfsja2

e3bfsja21#

我认为“你缺少的”是表达式progress.Report(++complete / total * 100)中的整数除法。当我复制这个问题时,这个表达式总是求值为零,除非total变量被转换为浮点变量类型。
除此之外,我能够重现一个模拟版本的代码与预期的结果。

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
        buttonUnzip.Click += onButtonUnzip;
    }
    private async void onButtonUnzip(object? sender, EventArgs e)
    {
        progressBar1.Visible = true;
        Progress<int> progress = new Progress<int>(value => {
            progressBar1.Value = value; progressBar1.Update();
        });
        await Task.Run(() => FileUtils.UnzipTo("mockSource", "mockDest", true, progress));
        progressBar1.Visible = false;
    }
}
class FileUtils
{
    static string[] GetFilesMock() => new string[25];
    static void UnzipOneMock(string sourceDir, string targetDir, string file) 
        => Thread.Sleep(TimeSpan.FromMilliseconds(100));
    public static void UnzipTo(
        string sourceDir,
        string targetDir,
        bool option, 
        IProgress<int> progress)
    {
        var files = GetFilesMock();
        int complete = 0;
        int total = files.Length;
        foreach (var file in files)
        {
            UnzipOneMock(sourceDir, targetDir, file);
            progress.Report((int)(++complete / (double)total * 100));
        }
    }
}

相关问题