我正在尝试使用我的应用中的进度条实现后台工作者。 我的应用程序做的是检查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
答案 0 :(得分:2)
我认为这是我的错误。这是在正确的地方吗?
使用while (worker.IsBusy) {}
会失败BackgroundWorker
的目的。顾名思义它应该在后台完成工作。使用类似于while的循环,你可能只需要在UI线程上工作。
您可以简单地删除此循环,BackgroundWorker仍将执行工作并报告进度。您可能必须确保在完成工作之前不能再次按下按钮。
我在进度条和背景工作者看到的所有示例通常都没有工人的DoWork中的方法。
我不确定您检查了哪些示例,但报告进展的唯一位置是DoWork
事件。这是实际知道它将做多少以及可能需要多长时间的唯一方法。
关于进度条:在理想的世界中,您有一个进度条,它以线性方式随时间改变其值。为何与时间?因为这样可以让用户了解他必须等待多长时间。
不幸的是,很难估计总时间或剩余时间。因此,您必须具有创造性,就像您在4种方法中的每种方法中所做的那样,只有25%。这有效,但并不是很好,因为那些25%的步骤有点太大了。其他可能性是报告处理的文件或字节的进度。
答案 1 :(得分:1)
您必须在DoWork
方法或您正在调用的方法中更新进度。简单地循环和递增进度没有意义,您必须在读取或复制文件等特定步骤之后执行此操作。