Как отменить Async Загрузка одного файла с несколькими загрузками файлов?

Я использую некоторый код для загрузки нескольких файлов, который работает хорошо. загружая много файлов, я хотел бы иметь возможность отменить их. Помимо пользовательского интерфейса с кнопкой отмены я использую в качестве глобальных переменных:

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" - это объект, который содержит идентификатор источника исходного источника данных, который я использую в wc_DownloadProgressChanged и wc_DownloadFileCompleted для определения правильных данных из моего источника данных.

В функции wc_DownloadFileCompleted я использую if (e.Cancelled), чтобы определить, была ли загрузка отменена.

Я пытаюсь отменить конкретную загрузку. Функция 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 ответ

Наконец я нашел решение для этого. Для тех, у кого такая же проблема, вот мое решение.

Использование 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; }
}

Класс теперь содержит свойство для 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 {  ...}));
}

Надеюсь, это поможет.. Я довольно долго искал, чтобы найти решение.

Другие вопросы по тегам