BackgroundWorker没有';t报告文件复制进度
本文关键字:文件 复制 报告 没有 BackgroundWorker | 更新日期: 2023-09-27 18:29:20
我正在使用C#和Winforms制作和应用程序,将文件夹归档并保存到指定位置,对于归档文件夹,我有一个BackgroundWorker,它将文件夹路径作为输入并生成zip归档。现在,在下一步中,需要将文件移动到指定的位置,同样,由于文件足够大,可能会挂起UI线程,我将代码移动到另一个名为FileMove的BackgroundWorker,除了FileMove 我面临的问题是,一旦文件移动开始label3就会显示"正在保存文件,请稍候…",并且在很长一段时间后(因为我正在压缩900-1000 MB),它会显示"文件夹已成功隐藏。"。在ProgressChanged过程中,事件标签也应该显示Percentage,但它没有。请指出或更正我的错误。任何帮助都将不胜感激。 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;
}
首先,您的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();
}
}
}