Как отменить 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 { ...}));
}
Надеюсь, это поможет.. Я довольно долго искал, чтобы найти решение.