C#使用已启动列表<>

时间:2016-08-23 19:33:31

标签: c# asynchronous multitasking cancellationtokensource cancellation-token

我开始使用列表任务并等待Task.WhenAll

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

那是我用list开始任务的代码。

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();
}

2 个答案:

答案 0 :(得分: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.");
    .
    .
    .
}

答案 1 :(得分:1)

WebClient没有采取CancelationToken,这很奇怪。相反,它有一个方法CancelAsync,您可以调用取消待处理的呼叫。

似乎您必须保持对您的webClient的引用,并在单击取消按钮时调用该方法。