我正在尝试编写一个C#Windows应用程序,它下载一个文件(等待下载完成-提供一些进度指标),然后执行下载的文件。我想我要么需要:
- 具有进度指示器且不会使我的应用程序无响应的同步下载
- 异步下载,等待下载完成,然后尝试执行
前者(同步下载)似乎可以随心所欲,但我找不到任何方式来指示进度,而且它似乎使我的程序没有响应(就像它挂起了一样),这可能会导致用户关闭应用程序,而不是等待它完成下载。
稍后的(异步下载)我已经能够用进度指示器等完成,但实际情况是下载开始,我的应用程序在下载完成之前立即尝试安装它,当然失败了。
那么,实现这一目标的最佳方法是什么呢?下面是我目前拥有的带有进度条的异步下载代码。
编辑2012年10月4日
旧的代码处理起来越来越麻烦,所以这就是我目前所拥有的。除了不更新进度条之外,它还能工作。
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
List<App> FilesToDownload = e.Argument as List<App>;
foreach (App Program in FilesToDownload) // Loop through List with foreach
{
//string Text = ;
UpdateRichTextBox("Downloading " + Program.Filename + "... Please wait");
string Source = Program.DownloadLocation + "/" + Program.Filename;
string Destination = System.AppDomain.CurrentDomain.BaseDirectory + Program.Filename;
WebClient webClient = new WebClient();
webClient.DownloadFile(Source, @Destination);
}
UpdateRichTextBox("File download complete");
foreach (App Program in FilesToDownload) // Loop through List with foreach
{
string Filename = Program.Filename;
string Arguments = Program.InstallParameters;
if (Filename != "advisorinstaller.exe")
{
Process p = new Process();
p.StartInfo.FileName = System.AppDomain.CurrentDomain.BaseDirectory + Filename;
p.StartInfo.Arguments = Arguments;
p.Start();
p.WaitForExit();
}
else
{
MessageBox.Show("About to install Belarc Advisor. This may take 10-15 minutes to run - do not shutdown this program. Click OK when ready to proceed.");
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
UpdateRichTextBox("Install Complete");
}
编辑2012年11月4日
所以我编辑了我的后台工作人员的工作如下:
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
List<App> FilesToDownload = e.Argument as List<App>;
int counter = 0;
int percent = 0;
foreach (App Program in FilesToDownload) // Loop through List with foreach
{
percent = ((counter / FilesToDownload.Count) * 100);
backgroundWorker1.ReportProgress(percent, "");
UpdateRichTextBox("Downloading " + Program.Filename + "... Please wait");
string Source = Program.DownloadLocation + "/" + Program.Filename;
string Destination = System.AppDomain.CurrentDomain.BaseDirectory + Program.Filename;
WebClient webClient = new WebClient();
webClient.DownloadFile(Source, @Destination);
counter++;
}
//backgroundWorker1.ReportProgress(100, "Complete!");
}
如果我取消对最后一行的注释,进度条将前进到100%。但它没有进展使用:
percent = ((counter / FilesToDownload.Count) * 100);
backgroundWorker1.ReportProgress(percent, "");
有什么想法吗?
您可以使用BackgroundWorker
在后台执行同步下载。它还支持进度报告。这将避免阻塞您的UI(因为下载在不同的线程上运行)。
您可以使用ManualResetEvent类在主线程上等待(使用WaitOne()),直到调用client_DownloadFileCompleted()事件处理程序(在对象上调用Set())。
您是否考虑过使用ClickOnce来执行此操作?它将通过自动更新解决您的问题。
查看以下SO问题,了解开始学习的地方:https://stackoverflow.com/questions/1635103/how-to-basic-tutorial-to-write-a-clickonce-app.
无需将WebClient
封装在BackgroundWorker
中,因为它已经是异步的(使用线程池中的线程)。
注意:下面的示例是在编辑器中编写的,当我检查MSDN文档中的方法签名时,我很容易犯错误。
public void InstallSecuniaPSI()
{
var source = new Uri("http://www.webserver.com:8014/psisetup.exe");
var dest = Path.Combine(Path.GetTemp(), "Download_SecuniaPSI.exe");
var client = new WebClient();
client.DownloadProgressChanged += OnDownloadProgressChanged;
client.DownloadFileCompleted += OnDownloadComplete;
client.DownloadFileAsync(source, dest, dest);
}
private void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// report progress
Console.WriteLine("'{0}' downloaded {1} of {2} bytes. {3}% complete"(string)e.UserState, e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage);
}
private void OnDownloadComplete(object sender, AsyncCompletedEventArgs e)
{
// clean up
var client = (WebClient)sender;
client.DownloadProgressChanged -= OnDownloadProgressChanged;
client.DownloadFileCompleted -= OnDownloadComplete;
if (e.Error != null)
throw e.Error;
if (e.Cancelled)
Environment.Exit(1);
// install program
var downloadedFile = (string)e.UserState;
var processInfo = new ProcessStartInfo(downloadedFile, "/S");
processInfo.CreateNoWindow = true;
var installProcess = Process.Start(processInfo);
installProcess.WaitForExit();
Environment.Exit(installProcess.ExitCode);
}
现在唯一需要排序的是如何让程序等待;如果是控制台程序,则在CCD_ 5之后调用CCD_。
HTH、