使用进度条

时间:2016-09-17 21:42:13

标签: c# .net asynchronous webclient

我试图从我的网络服务器下载文件夹,我想在进度条上显示已下载的数据量/要下载的总数量。首先,我尝试使用WebClient.DownloadFile。哪个完美无瑕,但它并没有触发DownloadProgressChangedEventHandler。我猜它只能通过异步下载激活。所以我将我的方法改写为WebClient.DownloadFileAsync。这是它变得复杂的地方。

例如,我的Web服务器上有30个文件,大小为53 MB。我想下载所有30个文件并在进度条上显示下载的进度(并在其下显示带有xx / 53 MB下载的标签)。

//Inicialized by opening dialog
private void DownloadForm_Shown(object sender, EventArgs e) {
   WebClient client = new WebClient();
   client.DownloadProgressChanged += client_DownloadProgressChanged;
   client.DownloadFileCompleted += client_DownloadFileCompleted;
   startDownload();
}

void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
    progressBar.Value = e.ProgressPercentage;
    labelProgress.Text = String.Format("Downloaded {0} of {1} bytes", e.BytesReceived, e.TotalBytesToReceive);
}

private void startDownload() {
   //files contains all URL links
   foreach (string str in files) {
      string urlDownload = HttpUtility.UrlPathEncode(str);
      //location is variable where file will be stored
      client.DownloadFileAsync(new Uri(urlDownload), location);

      //without this, async download will go crazy and wont download anything
      while (client.IsBusy) { }
   }
}

我有这个代码,它发生了什么,它将开始下载,但它不会更新进度条,也不会更新标签。下载后,它将在大约0.5秒内更新进度和标签,这就是它。我是这类人的初学者,你能帮我找一个错误吗?我知道如何为一个文件创建进度条。但我要做的是为多个文件制作它?

编辑:可以在此处找到包含某些解决方案的完整代码:http://pastebin.com/Hu4CCY8M 但是在调用downloadURLs()方法后,UI将冻结。完成此方法后它将再次开始工作。

1 个答案:

答案 0 :(得分:3)

如果没有可靠地再现问题的好Minimal, Complete, and Verifiable code example,就不可能完全解决问题。也就是说,从你发布的代码中可以清楚地看出,这里的主要问题是你已经阻止了UI线程,阻止了进度条的任何更改在下载过程中反映在用户界面上。

“疯狂”不是一个精确的问题描述,甚至接近一个。也就是说,我希望尝试同时启动所有下载以使WebClient对象沿“WebClient不支持并发I / O操作”抛出异常 。如果你想(也许你应该想要)同时下载文件,你需要有多个WebClient对象,每个并发下载一个。

鉴于您明确意图一次下载一个文件,您需要这样做而不会阻止UI线程。您发布的代码甚至可能不是原始代码的精确复制/粘贴,因为您在client方法中使用标识符startDownload()而不在任何地方声明,并且没有它可能是与client方法中的局部变量DownloadForm_Shown()相同。因此,暂时忽略这种差异,这里是您发布的代码的变体,它将名义上解决您的问题:

private TaskCompletionSource<bool> _tcs;

private async void DownloadForm_Shown(object sender, EventArgs e) {
   WebClient client = new WebClient();
   client.DownloadProgressChanged += client_DownloadProgressChanged;
   client.DownloadFileCompleted += client_DownloadFileCompleted;
   await startDownload(client);
}

void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
    progressBar.Value = e.ProgressPercentage;
    labelProgress.Text = String.Format("Downloaded {0} of {1} bytes", e.BytesReceived, e.TotalBytesToReceive);
}

void client_DownloadFileCompleted(object sender, DownloadFileCompletedEventArgs e) {
    // whatever else you have in this event handler, and then...
    _tcs.SetResult(true);
}

private async Task startDownload(WebClient client) {
   //files contains all URL links
   foreach (string str in files) {
      string urlDownload = HttpUtility.UrlPathEncode(str);
      //location is variable where file will be stored
      _tcs = new TaskCompletionSource<bool>();
      client.DownloadFileAsync(new Uri(urlDownload), location);
      await _tcs.Task;
   }
   _tcs = null; 
}

这样,DownloadForm_Shown()方法将在下载进行时将控制权返回给UI线程。每个下载的文件完成后,执行将在startDownload()方法中恢复,以便下一个文件可以启动。

如果上述内容无法让您回到正轨,请改进问题,使其包含良好的MCVE和更准确的问题说明。