C# Отменить задачу с запущенным списком‹›

Я начал задачу со списками и жду Task.WhenAll

private async void btn_download_Click(object sender, EventArgs e)
    {
        .
        .
        .
        await DownloadMultipleFilesAsync(old_json);
        Console.WriteLine("Download completed.");
    }

и это мой код, запускающий задачу со списком.

private async Task DownloadMultipleFilesAsync(List<media> doclist)
    {
        var token = cancelTokenSource.Token;
        await Task.WhenAll(doclist.Select(doc => DownloadFileAsync(doc)));
        btn_download.Enabled = true;
    }

и мой метод загрузки

private async Task DownloadFileAsync(media media)
{
    .
    .
    .
    Console.WriteLine(media.no + media_ext + " started.");
    webClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
    await webClient.DownloadFileTaskAsync(new Uri(media.url), @downloadToDirectory);
    Console.WriteLine(media.no + media_ext + " finished.");
    .
    .
    .
}

Окно вывода такое:

1.jpg started.
2.jpg started.
3.jpg started.
4.jpg started.
5.jpg started.
6.jpg started.
7.jpg started.
8.jpg started.
9.jpg started.
10.jpg started.
11.jpg started.
12.jpg started.
13.jpg started.
14.jpg started.
15.jpg started.
16.jpg started.
17.jpg started.
18.jpg started.
19.jpg started.
1.jpg finished.
4.jpg finished.
2.jpg finished.
6.jpg finished.
8.jpg finished.
10.jpg finished.
3.jpg finished.
5.jpg finished.
12.jpg finished.
14.jpg finished.
7.jpg finished.
16.jpg finished.
18.jpg finished.
9.jpg finished.
11.jpg finished.
13.jpg finished.
15.jpg finished.
17.jpg finished.
19.jpg finished.
Download completed.

Я хочу нажать btn_cancel и отменить запуск задачи и дождаться завершения начатой ​​задачи.

private void btn_cancel_Click(object sender, EventArgs e)
{
    cancelTokenSource.Cancel();
    cancelTokenSource = new CancellationTokenSource();
}

person Soner B    schedule 23.08.2016    source источник
comment
А какой у тебя вопрос?   -  person Ralf Bönning    schedule 23.08.2016
comment
Используйте 1_   -  person Matias Cicero    schedule 23.08.2016
comment
@MatiasCicero Я не могу так использовать prntscr.com/c9iiql   -  person Soner B    schedule 23.08.2016
comment
@SonerB Вы не звонили ToArray() после Select ...   -  person Matias Cicero    schedule 23.08.2016
comment
@MatiasCicero, теперь я пытаюсь. Загрузка запуска и зависание программы при ее завершении.   -  person Soner B    schedule 23.08.2016


Ответы (2)


Что вам нужно сделать, так это передать маркер отмены вниз по цепочке вызовов, а затем использовать его, где это возможно, вам также необходимо зарегистрировать обратный вызов отмены для вызова WebClient.CancelAsync(), чтобы отменить загрузку.

private async void btn_download_Click(object sender, EventArgs e)
{
    .
    .
    .
    var token = cancelTokenSource.Token;
    try
    {
        await DownloadMultipleFilesAsync(old_json, token);
        Console.WriteLine("Download completed.");
    }
    catch(OperationCanceledException ex)
    {
        //If something other than our token caused the cancel bubble up the exception.
        if(ex.CancellationToken != token)
            throw;
    }
}


private async Task DownloadMultipleFilesAsync(List<media> doclist, CancellationToken token)
{
    await Task.WhenAll(doclist.Select(doc => DownloadFileAsync(doc, token));
    btn_download.Enabled = true;
}


private async Task DownloadFileAsync(media media, CancellationToken token)
{
    .
    .
    .
    Console.WriteLine(media.no + media_ext + " started.");
    webClient.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
    try
    {
        using(token.Register(() => webClient.CancelAsync()))
        {
            await webClient.DownloadFileTaskAsync(new Uri(media.url), @downloadToDirectory);
        }
    }            
    catch (WebException ex)
    {
        //Raise a OperationCanceledException if the request was canceled, otherwise bubble up the exception.
        if(ex.Status == WebExceptionStatus.RequestCanceled)
            throw new OperationCanceledException(token);
        else
            throw;
    }
    Console.WriteLine(media.no + media_ext + " finished.");
    .
    .
    .
}
person Scott Chamberlain    schedule 23.08.2016
comment
Большое тебе спасибо. Я пробовал и работает. Но окно вывода заполнено следующим образом: prntscr.com/c9j0pg - person Soner B; 23.08.2016
comment
Скорее всего, у вас не включен параметр Только мой код. что-то не так в блоке btn_download_Click catch, из-за которого исключения проходят. - person Scott Chamberlain; 23.08.2016

WebClient не принимает CancelationToken, что странно. Вместо этого у него есть метод CancelAsync вы можете позвонить, чтобы отменить ожидающие вызовы.

Похоже, вам нужно будет сохранить ссылку на свой веб-клиент и вызвать этот метод при нажатии кнопки отмены.

person Jonesopolis    schedule 23.08.2016
comment
Вам не нужно хранить его, просто используйте CancellationToken.Register и вызовите функцию из делегата, просто передайте токен в функцию по цепочке. - person Scott Chamberlain; 23.08.2016
comment
@ScottChamberlain, определенно, мило. Не использовал это раньше. Это определенно отвлекло бы детали реализации. - person Jonesopolis; 23.08.2016
comment
Я сожалею. Я изучаю C# и не знаю, как вставить CancellationToken. Зарегистрируйте мои методы. Можете ли вы объяснить мне или какой-нибудь пример? - person Soner B; 23.08.2016
comment
@SonerB посмотрите на ответ, который я опубликовал, я покажу вам, как изменить все методы для этого. - person Scott Chamberlain; 23.08.2016
comment
@SonerB Скотт дал вам полноценный ответ. Я бы использовал его и отметил как принятый ответ - person Jonesopolis; 23.08.2016