项目将创建一个 UI,其中包含用于启动进程和取消进程的按钮,如下图所示。 这些按钮名为 startButton
和 cancelButton
。
如果不想等待异步应用程序完成,可以设置一个按钮用来取消它。 通过遵循本主题中的示例,可以为下载一个或一组网站内容的应用程序添加一个取消按钮。
下列代码是取消单个任务示例的完整 MainWindow.xaml.cs 文件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Http;
using System.Threading;
namespace CancelATask
{
public partial class MainWindow : Window
{
//声明一个System.Threading.CancellationTokenSource.
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
//实例化CancellationTokenSource.
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
//如果请求取消,则发送令牌以携带消息。
int contentLength = await AccessTheWebAsync(cts.Token);
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
catch (OperationCanceledException)
{
//如果请求取消,则返回OperationCanceledException
resultsTextBox.Text += "\r\nDownload canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownload failed.\r\n";
}
//下载完成后,将CancellationTokenSource设置为空
cts = null;
}
//为Cancel 按钮添加一个事件处理程序。
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
//提供一个CancellationToken参数
async Task<int> AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
resultsTextBox.Text += String.Format("\r\nReady to download.\r\n");
//您可能需要放慢速度才能有机会取消。
await Task.Delay(2500);
//GetAsync返回一个Task<HttpResponseMessage>
//如果选择Cancel按钮,则ct参数将携带消息。
HttpResponseMessage response = await client.GetAsync("http://www.twitter.com/dd470362.aspx", ct);
//从HttpResponseMessage中检索网站内容
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
//该方法的结果是下载网站页面的字符长度
return urlContents.Length;
}
}
// 成功下载的输出:
// Ready to download.
// Length of the downloaded string: 158125.
// 或者,如果取消:
// Ready to download.
// Download canceled.
}
下列代码是取消任务列表示例的完整 MainWindow.xaml.cs 文件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Http;
using System.Threading;
namespace CancelAListOfTasks
{
public partial class MainWindow : Window
{
//声明一个System.Threading.CancellationTokenSource.
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownloads complete.";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.";
}
cts = null;
}
//为Cancel 按钮添加一个事件处理程序。
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
//将返回类型更改为Task,因为该方法没有返回语句。
async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
//调用SetUpURLList来创建一个Web地址列表
List<string> urlList = SetUpURLList();
//添加一个循环来处理网址列表
foreach (var url in urlList)
{
//GetAsync返回一个Task<HttpResponseMessage>
//如果选择Cancel按钮,则ct参数将携带消息。
//请注意,取消按钮可以取消所有剩余的下载
HttpResponseMessage response = await client.GetAsync(url, ct);
//从HttpResponseMessage中检索网站内容
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", urlContents.Length);
}
}
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://www.twitter.com",
"http://www.twitter.com/hh290138.aspx",
"http://www.twitter.com/hh290140.aspx",
"http://www.twitter.com/dd470362.aspx",
"http://www.twitter.com/aa578028.aspx",
"http://www.twitter.com/ms404677.aspx",
"http://www.twitter.com/ff730837.aspx"
};
return urls;
}
}
//如果您不选择取消,则输出:
//Length of the downloaded string: 35939.
//Length of the downloaded string: 237682.
//Length of the downloaded string: 128607.
//Length of the downloaded string: 158124.
//Length of the downloaded string: 204890.
//Length of the downloaded string: 175488.
//Length of the downloaded string: 145790.
//Downloads complete.
//如果您选择取消:
//Length of the downloaded string: 35939.
//Length of the downloaded string: 237682.
//Length of the downloaded string: 128607.
//Downloads canceled.
}
如果不希望等待操作结束,可使用 CancellationTokenSource.CancelAfter
方法在一段时间后取消异步操作。 此方法会计划取消未在 CancelAfter
表达式指定的时间段内完成的任何关联任务。
请注意,必须为 System.Net.Http
添加引用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Http;
using System.Threading;
namespace CancelAfterTime
{
public partial class MainWindow : Window
{
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
//设置CancellationTokenSource以在2.5秒后取消。 (您可以调整时间。)
cts.CancelAfter(2500);
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownloads succeeded.\r\n";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
cts = null;
}
//您仍然可以使用取消按钮。
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
List<string> urlList = SetUpURLList();
foreach (var url in urlList)
{
//取消按钮取消所有剩余的下载。
HttpResponseMessage response = await client.GetAsync(url, ct);
//从HttpResponseMessage中检索网站内容
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", urlContents.Length);
}
}
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://www.twitter.com",
"http://www.twitter.com/ee256749.aspx",
...
};
return urls;
}
}
//示例输出:
// Length of the downloaded string: 35990.
// Length of the downloaded string: 407399.
// Length of the downloaded string: 226091.
// Downloads canceled.
}
通过结合使用 Task.WhenAny
方法和 CancellationToken
,可在一个任务完成时取消所有剩余任务。WhenAny
方法采用任务集合中的一个参数。该方法启动所有任务,并返回单个任务。 当集合中任意任务完成时,完成单个任务。
此示例演示如何结合使用取消标记与 WhenAny
保留任务集合中第一个要完成的任务,并取消剩余任务。 每个任务都下载网站内容。
本示例显示第一个完成的下载的内容长度,并取消其他下载。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Http;
using System.Threading;
namespace CancelAfterOneTask
{
public partial class MainWindow : Window
{
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownload complete.";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownload canceled.";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownload failed.";
}
cts = null;
}
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
List<string> urlList = SetUpURLList();
//创建一个查询,该查询在执行时返回一组任务。
IEnumerable<Task<int>> downloadTasksQuery =
from url in urlList select ProcessURLAsync(url, client, ct);
//使用ToArray执行查询并开始下载任务
Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
//调用WhenAny然后等待结果。首先完成的任务分配给firstFinishedTask。
Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
//取消下载的其余部分,你只是想要第一个。
cts.Cancel();
//等待第一个完成的任务并显示结果。
var length = await firstFinishedTask;
resultsTextBox.Text += String.Format("\r\nLength of the downloaded website: {0}\r\n", length);
}
//将网站的处理步骤集中到一个异步方法中。
async Task<int> ProcessURLAsync(string url, HttpClient client, CancellationToken ct)
{
//GetAsync返回一个Task<HttpResponseMessage>
HttpResponseMessage response = await client.GetAsync(url, ct);
//从HttpResponseMessage中检索网站内容
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
return urlContents.Length;
}
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://www.twitter.com",
"http://www.twitter.com/hh290138.aspx",
"http://www.twitter.com/hh290140.aspx",
...
};
return urls;
}
}
//示例输出:
// Length of the downloaded website: 158856
// Download complete.
}
通过使用 Task.WhenAny
,可以同时启动多个任务,并在它们完成时逐个对它们进行处理,而不是按照它们的启动顺序进行处理。
下面的示例使用查询来创建一组任务。 每个任务都下载指定网站的内容。 在对 while 循环的每次迭代中,对 WhenAny
的等待调用返回任务集合中首先完成下载的任务。 此任务从集合中删除并进行处理。 循环重复进行,直到集合中不包含任何任务。
请注意,必须为 System.Net.Http
添加引用。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Http;
using System.Threading;
阅读量:2011
点赞量:0
收藏量:0