BackgroundWorker没有';t报告文件复制进度

本文关键字:文件 复制 报告 没有 BackgroundWorker | 更新日期: 2023-09-27 18:29:20

我正在使用C#和Winforms制作和应用程序,将文件夹归档并保存到指定位置,对于归档文件夹,我有一个BackgroundWorker,它将文件夹路径作为输入并生成zip归档。现在,在下一步中,需要将文件移动到指定的位置,同样,由于文件足够大,可能会挂起UI线程,我将代码移动到另一个名为FileMoveBackgroundWorker,除了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过程中,事件标签也应该显示Percentage,但它没有。请指出或更正我的错误。任何帮助都将不胜感激。

BackgroundWorker没有';t报告文件复制进度

首先,您的BackgroundWorker正试图从其后台线程更新UI,这在多线程UI应用程序中是不允许的。

要更新UI,您需要切换到UI线程进行更新。这是通过首先检查label3.InvokeRequired是否为true(表示不能从当前线程更新UI),然后将委托传递给label3.Invoke(not Delegate.Invoke())来完成的

这是WinForms开发需要非常熟悉的模式。ControlInvokeMSDN页面包含了一个利用此模式的示例。

其次,您需要周期性地调用BackgroundWorker.ReportProgress(),它会激发具有百分比完成值的ProgressChanged事件。


这是一个示例应用程序。它假设你有一个带按钮、标签的Form和一个带WorkgerReportsProgress = true(和WorkerSupportsCancellation = true,用于奖励积分)的BackgroundWorker。

当你点击按钮时,它会启动一个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();
    }
  }
}