我会尽量简化我的情况,使其更加简洁明了。所以,我正在开发一个 WinRT 应用程序,用户在TextBox
和TextChanged
事件中输入文本,经过2秒后,我需要提取远程请求来获取基于用户文本的数据。
现在,用户输入文本并初始化了Web请求,但用户立即编写了另一个术语。因此,我需要取消第一个Web请求并启动新请求。
请将以下内容视为我的代码:
private CancellationTokenSource cts;
public HomePageViewModel()
{
cts = new CancellationTokenSource();
}
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
//Cancel previous request before making new one
//GetMembers() is using simple HttpClient to PostAsync() and get response
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
}
我知道CancellationToken
在这里发挥了作用,但我无法弄清楚如何。
答案 0 :(得分:5)
你已经差不多了。核心思想是单个CancellationTokenSource
只能被取消一次,因此必须为每个操作创建一个新的。{/ p>
private CancellationTokenSource cts;
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
{
// If there's a previous request, cancel it.
if (cts != null)
cts.Cancel();
// Create a CTS for this request.
cts = new CancellationTokenSource();
try
{
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
}
catch (OperationCanceledException)
{
// This happens if this operation was cancelled.
}
}
答案 1 :(得分:0)
我会像这样实现GetMembers
方法:
private async Task<List<Member>> GetMembers(int id, CancellationToken token)
{
try
{
token.ThrowIfCancellationRequested();
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
{
response = await client.PostAsync(new Uri("http://apiendpoint"), content)
.AsTask(token);
}
token.ThrowIfCancellationRequested();
// Parse response and return result
}
catch (OperationCanceledException ocex)
{
return null;
}
}
其余的只是调用cts.Cancel()
方法并在每次在处理程序中调用CancellationTokenSource
之前创建GetMembers
的新实例。当然,正如@Russell Hickey所说,cts
应该是全球性的。 (如果有这个类的多个实例,甚至是静态的,并且你总是想在调用这个处理程序时取消GetMembers
方法。通常我也有一个包装结果的类,并且有一个额外的属性{{1}将真实的IsSuccessful
结果与失败的操作区分开来。