我正在使用Visual Studio中的WPF应用程序,我需要下载一个大文件并在我的代码中提取它。有人建议我使用后台工作人员,但现在当我尝试增加进度条上的值时,它不起作用......有人可以帮忙吗?
public void InstallVersion(string version)
{
string location = File.ReadAllText(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\MidnightFallsLauncher\data\locator.txt");
location = location + @"\Versions\" + version;
if (File.Exists(location + ".zip"))
File.Delete(location + ".zip");
if (Directory.Exists(location))
{
DirectoryInfo di = new DirectoryInfo(location);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in di.GetDirectories())
{
dir.Delete(true);
}
}
if (!myWorker.IsBusy)
{
myWorker.RunWorkerAsync();
}
}
这是我的工人代码
public MainWindow()
{
InitializeComponent();
myWorker.DoWork += new DoWorkEventHandler(myWorker_DoWork);
myWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted);
myWorker.ProgressChanged += new ProgressChangedEventHandler(myWorker_ProgressChanged);
myWorker.WorkerReportsProgress = true;
myWorker.WorkerSupportsCancellation = true;
}
protected void myWorker_DoWork(object sender, DoWorkEventArgs e)
{
string location = File.ReadAllText(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\MidnightFallsLauncher\data\locator.txt");
location = location + @"\Versions\" + Version;
WebClient Client = new WebClient();
string url = "";
string content = "";
string downloadlink = "";
List<string> availibleVersions = new List<string>();
List<string> versionDownload = new List<string>();
url = "https://midnightfalls.glitch.me/versions.html";
content = Client.DownloadString(url);
foreach (string line in content.Split(new string[] { "<br>", "<br />" }, StringSplitOptions.None))
{
if (line.Contains("0"))
{
availibleVersions.Add(line);
}
}
url = "https://midnightfalls.glitch.me/versionslink.html";
content = Client.DownloadString(url);
foreach (string line in content.Split(new string[] { "<br>", "<br />" }, StringSplitOptions.None))
{
if (line.Contains("https"))
{
versionDownload.Add(line);
}
}
for (var i = 0; i < availibleVersions.Count; i++)
{
if (availibleVersions[i] == Version)
{
downloadlink = versionDownload[i];
}
}
Client.DownloadFile(downloadlink, location + ".zip");
ZipFile.ExtractToDirectory(location + ".zip", location);
File.Delete(location + ".zip");
RunGame(Version);
}
protected void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
protected void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.Dispatcher.Invoke(() =>
{
progress.Value += 10;
});
}
此外,当我的工作人员正在运行时,用户界面冻结......我非常确定这不会发生。
修改 用户界面现在正在更新,但进度条仍无效...
答案 0 :(得分:0)
我很确定你在这里阻止:
while (this.myWorker.IsBusy)
{
this.Dispatcher.Invoke(() =>
{
progress.Value += 10;
});
}
您应该在ReportProgress
方法中的BackgroundWorker
个实例上致电myWorker_DoWork
。
此外,如果您使用的是.NET 4.5或更高版本,则可以完全转储BackgroundWorker
并使用async
/ await
模式重写此代码。
答案 1 :(得分:0)
看起来问题是主要线程在后台工作者正在工作时不断工作:
while (this.myWorker.IsBusy)
{
this.Dispatcher.Invoke(() =>
{
progress.Value += 10;
});
}
表示您的主线程在后台作业正在工作时不断地执行操作,这就是UI无法更新的原因。
您需要将进度更新移动到后台工作程序(您还可以在其中设置实际上有意义的值,例如,指示您已下载了多少“可用版本”)。 / p>
希望这是有道理的。
编辑:
假设我们将所有代码直接放在视图中,假设我们有一个名为&#39; progressBar&#39;的进度条。以及一个名为&#39; btnStart&#39;的按钮(背景工作者的踢法)。
这里是代码隐藏:
private BackgroundWorker worker;
public MainWindow()
{
InitializeComponent();
this.worker = new BackgroundWorker();
this.worker.DoWork += new DoWorkEventHandler(myWorker_DoWork);
this.worker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted);
this.worker.ProgressChanged += new
ProgressChangedEventHandler(myWorker_ProgressChanged);
this.worker.WorkerReportsProgress = true;
this.worker.WorkerSupportsCancellation = true;
}
private void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar.Value = e.ProgressPercentage;
}
private void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Whatever you need to do when finished here (alert, update a label, etc.)
}
private void myWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Just loop and report new progress. Sleep a little in between each
// progress update so that it isn't over before we have a chance to see it.
for(int i=0;i<100;i++)
{
Thread.Sleep(200);
this.worker.ReportProgress(i);
}
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
this.worker.RunWorkerAsync();
}
后台工作人员触发事件通知进度已发生变化。 主线程具有该事件的句柄,并更新进度条。 由于它是后台工作人员,因此您不需要使用Dispatcher.Invoke - 这已经得到了解决。
希望这个例子能为你澄清事情。