进度报告:需要帮助了解它是如何工作的

Progress report : Need help understanding how it works

我发现了这一点,但无法理解它是如何工作的。 我的主窗体中有一个进度条,mysql 数据库上有一个带有一些维护功能的 menuStrip。我想监控他们每个人的进度。 所以我有 class reportProgress 的进步。 我的声明如下:

 ProgressReportModel report = new ProgressReportModel();
 Progress<ProgressReportModel> progress = new Progress<ProgressReportModel>();
 progress.ProgressChanged += ReportProgress;

现在对于每个功能,我通常从 :

        report.max = count;
        report.visibility = true;
        report.PercentageComplete = 0;
        showtheProgress(progress);

使用 ShowtheProgress,因为我没有找到将 Progress 转换为 IProgress 的方法:

   private void showtheProgress(IProgress<ProgressReportModel> progress)
    {
        progress.Report(report);
    }

我的问题是这对某些功能有效,但对所有功能无效。 一个区别是我可以看到它是否适用于 async 的函数,但不适用于非异步的函数。为了避免代码泛滥,只需放置一个不起作用的函数(即进度条甚至没有显示):

    private void getMp3Files()
    {
        Globals.counttot = Directory.GetFiles(Globals.pathdir, "*.mp3", SearchOption.AllDirectories).Length;
        report.max = Globals.counttot;
        report.visibility = true;
        report.PercentageComplete = x; 
        showtheProgress(progress);
        DirectoryCopy(Globals.pathdir);
        report.visibility = false;
        report.PercentageComplete = 0;
        showtheProgress(progress);
    }
    private void DirectoryCopy(string sourceDirName)
    {
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);
        DirectoryInfo[] dirs = dir.GetDirectories();
        FileInfo[] files = dir.GetFiles("*.mp3");
        foreach (FileInfo file in files)
        {
            string temppath = Path.Combine(sourceDirName, file.Name);
            Mp3 tmp_mp3 = Globals.getTags(temppath);
            Globals.AddRowDs(tmp_mp3, false);
            report.PercentageComplete = x; //not part of this code but it's a counter
            showtheProgress(progress);
        }
        foreach (DirectoryInfo subdir in dirs) DirectoryCopy(subdir.FullName);
    }

提前致谢!

从您发布的代码中看不完全清楚,但我猜您遇到这个问题是因为 winforms 如何处理线程以及异步 'invented' 的原因之一。

windows 表单基于消息队列之类的东西。您在该表单上所做的一切,例如移动鼠标、单击按钮、moving/resizing 表单、键入等等,都将转换为事件并放入此队列中。在后台,有一些东西不断地检查这个队列中的新事件并执行它们,其中一个事件是绘制屏幕(paint),基本上是在屏幕上显示你的表单。您只能看到在这些绘制事件期间所做的更改(如显示进度条)。如果这些绘制事件之间的时间太长,您会看到消息 "Not responding"。

其中一些事件也是单击按钮,这些事件将执行您编写的所有代码。如果这个事件的处理时间太长,那么你就会阻塞消息队列并创建"Not responding"消息。为了避免这种情况,建议让这些事件尽可能快,如果你想执行一些需要很长时间的事情,在另一个线程上进行(参见BackgroundWorker for an example). One downside of this is that it's not easy to communicate with the form (typically checking InvokeRequired and calling Invoke

这里是 async/await 来帮助您的地方。如果您单击按钮,并且您的代码遇到尚未完成的 await,那么它将添加一些代码,一旦等待的方法完成,它将向消息队列添加一个事件以继续代码中的这一点并结束事件。这意味着消息队列中的其余事件(如显示进度条、显示一些文本或处理其他按钮点击)是可能的。

为了完整起见,有些人建议您可以在代码中添加 Application.DoEvents(),这将强制在您仍在方法中时处理消息队列。这是一种快速而肮脏的方式,有些人在不知道其全部含义的情况下采取了这种方式。知道它存在但要避免它。