Howto取消异步下载一个文件witihn多文件下载?

时间:2017-06-04 12:06:06

标签: c# .net async-await webclient cancellationtokensource

我使用一些代码来下载多个文件,这很好用。 在下载大量文件时,我希望能够取消它们。 除了带有取消按钮的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();
    }

我如何实现这一目标?

1 个答案:

答案 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 {  ...}));
}

希望这有帮助..我找了很长时间才找到解决方案。