如何在后台工作程序复制文件时正确增加进度条

时间:2014-08-08 10:13:49

标签: c# progress-bar backgroundworker

我正在尝试使用我的应用中的进度条实现后台工作者。 我的应用程序做的是检查PC上是否存在某些文件。如果他们不这样做,它会将文件从服务器复制到PC。它还检查文件是否已存在,以查看是否有任何较新版本的文件可供下载。如果是这样,它会复制它们。

我想实现一个带有进度条的后台工作程序,以向用户显示它已完成的工作量。我的工作包括4种方法,用于检查和复制文件。这就是我感到困惑的地方。我在进度条和后台工作者看到的所有示例通常都没有在工作者的DoWork中使用方法。

这是我的代码:

private void btnClick_Click(object sender, EventArgs e)
    {
        Form1 frm = new Form1();
        frm.Enabled = false; //to insure the user doesn't close the form until the progress is completed
        worker = new BackgroundWorker();
        worker.WorkerSupportsCancellation = false;
        worker.DoWork += DoWork;
        worker.ProgressChanged += ProgressChanged;
        worker.WorkerReportsProgress = true;
        worker.RunWorkerAsync();
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        while (worker.IsBusy) //I think this is my mistake. Is this in the right place?
        {
            progressBar.Increment(1);
            Application.DoEvents();
        }

    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Form1 frm = new Form1();
        if (!(e.Error == null))
        {
            lblDisp.Text = e.Error.Message;
            frm.Enabled = true;
        }
        else
        {
            lblDisp.Text = "Done";
            frm.Enabled = true;
        }
    }//The form will then enable again and display a message once the worker is done

    private void ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
    }

    protected void DoWork(object sender, DoWorkEventArgs e)
    {
        //And these are the methods that work.
        FindFolders();
        FindFiles();
        ReplaceExeFile();
        CopyDllFiles();
    }

我的应用中的方法只是典型的复制和覆盖

string folderProg = @"C:\new\prog.exe";
        string debugProg = @"\\192.169.1.1\progfiles\prog.exe";

        var versionDebug = FileVersionInfo.GetVersionInfo(debugProg);
        var versionFolder = FileVersionInfo.GetVersionInfo(folderProg);
        Version verFold = new Version(versionFolder.FileVersion);
        Version verDeb = new Version(versionDebug.FileVersion);

        if (verDeb > verFold)
        {
            File.Copy(debugProg, folderProg, true);
        }

所以我知道这项工作没有任何问题。它复制。我的问题是在实际工作开始之前酒吧填满了。如果我移动增量代码,它不会填满100%。文件被复制,但栏只有10%已满。

基本上,我知道我已将增量代码放在错误的位置,但我不知道代码应该去哪里。

执行此操作的一种丑陋方式是在DoWork中放置worker.ReportProgress(25)并增加25,并在完成后填写它,同时在progressBar.Increment(1)代码中注释掉while (worker.IsBusy)。但这是因为我知道有4种方法(4 * 25)。 像这样:

private void btnClick_Click(object sender, EventArgs e)
    {
        Form1 frm = new Form1();
        frm.Enabled = false;
        worker = new BackgroundWorker();
        worker.WorkerSupportsCancellation = false;
        worker.DoWork += DoWork;
        worker.ProgressChanged += ProgressChanged;
        worker.WorkerReportsProgress = true;
        worker.RunWorkerAsync();
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        while (worker.IsBusy)
        {
            //progressBar.Increment(1);
            Application.DoEvents();
        }

    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Form1 frm = new Form1();
        if (!(e.Error == null))
        {
            lblDisp.Text = e.Error.Message;
            frm.Enabled = true;
        }
        else
        {
            lblDisp.Text = "Done";
            frm.Enabled = true;
        }
    }

    private void ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
    }

    protected void DoWork(object sender, DoWorkEventArgs e)
    {
        FindFolders();
        worker.ReportProgress(25);
        FindFiles();
        worker.ReportProgress(50);
        ReplaceExeFile();
        worker.ReportProgress(75);
        CopyDllFiles();
        worker.ReportProgress(100);
    }

这种方式确实有效。但是还不是另一个吗?

EDIT。 只是为了澄清,我的用法:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

我正在使用.NET Framework 4

2 个答案:

答案 0 :(得分:2)

  

我认为这是我的错误。这是在正确的地方吗?

使用while (worker.IsBusy) {}会失败BackgroundWorker的目的。顾名思义它应该在后台完成工作。使用类似于while的循环,你可能只需要在UI线程上工作。

您可以简单地删除此循环,BackgroundWorker仍将执行工作并报告进度。您可能必须确保在完成工作之前不能再次按下按钮。

  

我在进度条和背景工作者看到的所有示例通常都没有工人的DoWork中的方法。

我不确定您检查了哪些示例,但报告进展的唯一位置是DoWork事件。这是实际知道它将做多少以及可能需要多长时间的唯一方法。

关于进度条:在理想的世界中,您有一个进度条,它以线性方式随时间改变其值。为何与时间?因为这样可以让用户了解他必须等待多长时间。

不幸的是,很难估计总时间或剩余时间。因此,您必须具有创造性,就像您在4种方法中的每种方法中所做的那样,只有25%。这有效,但并不是很好,因为那些25%的步骤有点太大了。其他可能性是报告处理的文件或字节的进度。

答案 1 :(得分:1)

您必须在DoWork方法或您正在调用的方法中更新进度。简单地循环和递增进度没有意义,您必须在读取或复制文件等特定步骤之后执行此操作。