BackgroundWorker不报告文件复制进度?

时间:2013-08-28 21:13:48

标签: c# multithreading winforms file

我正在使用C#和Winforms进行存档并将文件夹保存到指定位置,对于存档文件夹,我有一个 BackgroundWorker ,它将文件夹路径作为输入并生成一个zip存档。现在下一步该文件需要在指定的位置移动,再次因为文件足够大并且可以挂起UI线程我将代码移动到另一个名为 FileMove BackgroundWorker ,一切顺利,但 FileMove 没有报告任何进展,这是我在归档结束后立即调用的函数;

  private void FileMove_DoWork(object sender, DoWorkEventArgs e)
    {
        label3.Text = "Saving file,please wait...";
        File.Move(temppath + @"\Output.jpg", savefilename);
    }

    private void FileMove_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        label3.Text = "Saving file,please wait... " + e.ProgressPercentage.ToString(); //This should show Progress Percentage but it doesn't.
    }

    private void FileMove_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        label3.Text = ("The folder has been successfully hidden.");
        button1.Enabled = true;
        button2.Enabled = true;
        button3.Enabled = true;
        this.ControlBox = true;
    }

我面临的问题是,一旦文件移动开始 label3 显示“保存文件,请稍候......”并且经过很长时间(因为我压缩900-1000 MB) )它显示“文件夹已被成功隐藏。”。在ProgressChanged事件标签期间,标签也应显示百分比,但它不显示。请指出或纠正我出错的地方。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

首先,您的BackgroundWorker正在尝试从其后台线程更新UI,这在多线程UI应用程序中是禁止的。

要更新UI,您需要将其切换到UI线程以进行更新。首先检查label3.InvokeRequired是否为真(表示您无法从当前线程更新UI),然后将委托传递给label3.Invokenot Delegate.Invoke()

这是您需要非常熟悉WinForms开发的模式。 Control.Invoke MSDN页面包含了利用此模式的示例。

其次,您需要定期致电BackgroundWorker.ReportProgress(),这会以完整百分比值触发ProgressChanged事件。


这是一个示例应用。它假定您有一个带有Button,Label和BackgroundWorker的表单WorkgerReportsProgress = true(和WorkerSupportsCancellation = true,奖励积分)。

当您单击按钮时,它会启动一个5秒的阻止任务,然后切换到10个1秒的阻止任务(沿途报告进度)。

请注意帮助方法InvokeIfRequired(),确保从正确的线程更新UI。过度使用这一点没有任何害处。

public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }

  private void button1_Click(object sender, EventArgs e)
  {
    if (backgroundWorker1.IsBusy)
    {

      label1.Text = "Reset!";
      backgroundWorker1.CancelAsync();
      return;
    }

    backgroundWorker1.RunWorkerAsync();
  }

  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
  {
    label1.InvokeIfRequired(() => label1.Text = "Gettin busy");
    System.Threading.Thread.Sleep(5000);

    for (int i = 0; i < 10; i++)
    {
      backgroundWorker1.ReportProgress(i*10);
      System.Threading.Thread.Sleep(1000);
    }
  }

  private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  {
    label1.InvokeIfRequired(() => label1.Text = "Done");
  }

  private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
  {
    label1.InvokeIfRequired(() => label1.Text = string.Format("{0}% done", e.ProgressPercentage));
  }
}

public static class InvokeExtensions
{
  public static void InvokeIfRequired(this ISynchronizeInvoke control, MethodInvoker action)
  {
    if (control.InvokeRequired)
    {
      control.Invoke(action, null);
    }
    else
    {
      action();
    }
  }
}