正确使用进度条

Posted

技术标签:

【中文标题】正确使用进度条【英文标题】:Proper use of progress bar 【发布时间】:2016-08-14 07:16:53 【问题描述】:

这是我第一次在 C# 中使用进度条。 我的代码正在复制一些文件,我想通过进度条显示进度。

我不喜欢我的代码的一点是,我必须通过所有文件来设置栏的最大值……然后我再次通过相同的过程来复制文件。

如果不这样做,我就是想不出一种方法来确保在酒吧中顺利进行。我首先必须知道最大值对吗?还是有什么诀窍?

代码如下:

设置最大值:

private static void setProgressBar(List<Source> sources, List<Destination> destinations)

    progress.Value = 0;
    progress.Maximum = 0;

    foreach (var source in sources)
    
        progress.Maximum += System.IO.Directory.GetDirectories(source.directory, "*",
            SearchOption.AllDirectories).Count() * destinations.Count +
            System.IO.Directory.GetFiles(source.directory, "*.*", SearchOption.AllDirectories).Count() *
            destinations.Count;
    

复制文件:

public static void CopyData(List<Source> sources, List<Destination> destinations, RichTextBox box, ProgressBar bar)

    log = box;
    progress = bar;
    setProgressBar(sources, destinations);

    foreach (var source in sources)
    
        foreach (var dirPath in System.IO.Directory.GetDirectories(source.directory, "*",
            SearchOption.AllDirectories))
        
            foreach (var destination in destinations)
            
                logger(dirPath);
                System.IO.Directory.CreateDirectory(dirPath.Replace(source.directory, destination.directory));
            
        

        foreach (var newPath in System.IO.Directory.GetFiles(source.directory, "*.*", SearchOption.AllDirectories))
        
            foreach (var destination in destinations)
            
                logger(newPath);
                File.Copy(newPath, newPath.Replace(source.directory, destination.directory), true);
            
        
    

增加进度条:

私有静态无效记录器(字符串输出) log.Text += "复制:" + 输出 + System.Environment.NewLine; log.SelectionStart = log.Text.Length; log.ScrollToCaret(); 进度.增量(1);

所以我两次运行相同的代码......我不喜欢这样:)

【问题讨论】:

【参考方案1】:

我在这里看到两个错误:您从未在 CopyData 方法中设置进度条的值 第二个是:您的 CopyData 方法将导致您的 UI 冻结,直到该方法完成(此时进度条将从 0 跳转到 100%)。

您可以将 CopyData 方法放在 BackgroundWorker 中并调用 ReportProgress 并在 ReportProgress 事件中设置栏的新值。

这是一个如何完成的示例。而不是static void Main(..) 调用工作人员,您将从那里开始您的 CopyData 方法

static void Main(string[] args)

    System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
    worker.ProgressChanged += Worker_ProgressChanged;
    worker.DoWork += Worker_DoWork;

    //Do work
    worker.RunWorkerAsync();


private static void Worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)

    //Get Values
    var source = null;
    var destinations = null;

    //CopyData Method
    setProgressBar(sources, destinations);
    foreach (var source in sources)
    
        foreach (var dirPath in System.IO.Directory.GetDirectories(source.directory, "*", SearchOption.AllDirectories))
        
            foreach (var destination in destinations)
            
                logger(dirPath);
                System.IO.Directory.CreateDirectory(dirPath.Replace(source.directory, destination.directory));
                //Increase Value by 1
                (sender as System.ComponentModel.BackgroundWorker).ReportProgress(1);
            
        

        foreach (var newPath in System.IO.Directory.GetFiles(source.directory, "*.*", SearchOption.AllDirectories))
        
            foreach (var destination in destinations)
            
                logger(newPath);
                File.Copy(newPath, newPath.Replace(source.directory, destination.directory), true);
                //Increase Value by 1
                (sender as System.ComponentModel.BackgroundWorker).ReportProgress(1);
            
        
    


private static void Worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)

    if (e.ProgressPercentage == 1)
    
        //If Value gets higher than Maximum it will cause an Exception
        if (progress.Value < progress.Maximum)
            progress.Value += 1;
    


private static void setProgressBar(List sources, List destinations)

    progress.Value = 0;
    progress.Maximum = 0;
    foreach (var source in sources)
    
        foreach (var dirPath in System.IO.Directory.GetDirectories(source.directory, "*", SearchOption.AllDirectories))
        
            //Simplified
            progress.Maximum += destinations.Count;
        

        foreach (var newPath in System.IO.Directory.GetFiles(source.directory, "*.*", SearchOption.AllDirectories))
        
            //Simplified
            progress.Maximum += destinations.Count;
        
    

【讨论】:

感谢您的回复,首先缺少一个方法,因此您看不到我确实在logger(newPath) 方法中增加了进度条的值。所以它不会从 0 跳到 100。其次,通过 BackgroundWorker 执行此操作并不能改善性能最密集的代码(您简化的代码)运行两次的情况!想象一下,有 2000 个目录,程序会减慢 1.5。 - 2次。我正在寻找一种方法来改善它。不知道有没有可能 我又读了几篇关于后台工作人员的文章,发现它们在不同的线程中运行。所以我认为你的回答对我有帮助! 很高兴听到 :) 关于性能密集型代码的另一个问题。您可以忽略直到您写入文件的目录并检查目标文件的目录是否存在。如果没有 -> 创建它。到目前为止,这将是我对这部分问题的唯一想法。

以上是关于正确使用进度条的主要内容,如果未能解决你的问题,请参考以下文章

Flexbox 进度条动画 - 宽度不正确

Inno Setup - 正确定时更新进度条

NSURLSession 下载任务 - 进度条问题

如何显示ProgressBar的进度条,给分100

带有英雄单元文本的 Twitter Bootstrap 进度条未正确显示

如何使用逆时针动画显示自定义圆形进度条?