我使用一些代码来下载多个文件,这很好用。 在下载大量文件时,我希望能够取消它们。 除了带有取消按钮的UI我还用作全局变量:
private WebClient client = null;
private CancellationToken cts = new CancellationToken();
在我使用的下载功能中:
// The Object SourceId is only used to be able
// to pass the ID (index) of datasource to callback functions
var current = new SourceId();
current.Id = sourceList.IndexOf(current);
cts = new CancellationToken();
//i tried to use (cancellationToken.Register(() => webClient.CancelAsync())
using (client = new WebClient())
using (cts.Register(() => wc_Cancel()))
{
client.DownloadProgressChanged += wc_DownloadProgressChanged;
client.DownloadFileCompleted += wc_DownloadFileCompleted;
client.DownloadFileAsync(new Uri(driver.Filelink), targetFile, current);
}
“current”是一个对象,它包含原始数据源的源ID,我在wc_DownloadProgressChanged和wc_DownloadFileCompleted中使用它来从我的数据源中确定正确的数据。
在函数wc_DownloadFileCompleted中,我使用if(e.Cancelled)来确定下载是否被取消。
我尝试取消特定的下载。获取相应的源ID后,按钮会调用cancelDownload函数。
如何取消一个特定的异步下载,这意味着如何传递取消函数所需的参数?
private void cancelDownload(int id)
{
// Here i would like to send the ID to cancel to specific download
// and wait for it to finish. How can i do this ?
wc_Cancel();
}
public virtual void wc_Cancel()
{
if (this.client != null)
this.client.CancelAsync();
}
我如何实现这一目标?
答案 0 :(得分:1)
最后我找到了解决方案。对于那些有同样问题的人来说,这是我的解决方案。
使用CancellationToken不是必要的。此外,不需要函数cancelDownload和wc_Cancel。我使用了一个下载类,包含所有需要的信息,如FileLink,Name等。我确实使用这些属性扩展了该类:
// HelperClass to pass for callbacks
public class DownId
{
public int Id { get; set; }
}
// DownloadClass with all needed properties. Should be expanded for your needs.
public class Downloads
{
public Driver()
{
}
public string Title { get; set; }
public string Filelink { get; set; }
public string FileName { get; set; }
public bool IsCanceling { get; set; }
public WebClient Client { get; set; }
public int Retry { get; set; }
public int Progress { get; set; }
public long valBytesRec { get; set; }
public long valBytesTotal { get; set; }
}
Class现在包含用于取消的WebClient
和bool参数的属性。类型为List<Downloads>
的全局变量下载列表用于访问所有函数中所需的属性。
在下载功能中,我使用参数currentdriver,它是列表中当前下载的索引号(用作下载的参数):
DownId currentSourceId = new DownId();
currentSourceId.Id = currentdriver;
using (downloadlist[current].Client = new WebClient())
{
downloadlist[current].Client.DownloadProgressChanged += wc_DownloadProgressChanged;
downloadlist[current].Client.DownloadFileCompleted += wc_DownloadFileCompleted;
downloadlist[current].Client.DownloadFileAsync(new Uri(driver.Filelink), targetFile, currentSourceId);
}
为了能够将currentdrive
传递给DownloadFileAsync
,必须在对象中使用它。为此目的使用了DownId类。
这样每次下载都会使用自己的WebClient,访问非常简单。
要取消,只需在IsCanceling
事件处理程序中设置button_Click
属性:
driverlist[currentdriver].IsCanceling = true;
在wc_DownloadProgressChanged
中,我使用此代码来确定是否需要取消:
var currentDriver = e.UserState as DownId;
if (downloadlist[current].IsCanceling)
{
downloadlist[current].IsCanceling = false;
downloadlist[current].Client.CancelAsync();
}
else
{
//Update progress etc.
// beware of not using UI Elements here, caused UI Lags
// and can be a problem within threads
// if necessary use Invoke(new MethodInvoker(delegate { ...}));
}
希望这有帮助..我找了很长时间才找到解决方案。