2012-07-07 21 views
4

因此,我在我的UI上有一个组合框,它在SelectionChanged上异步退出到Web服务以撤回某些信息以在UI上显示(使用新的C#5 async/await关键字)。我想要做的是在发送新的请求之前取消当前的异步请求;例如,如果用户使用键盘快速遍历所有组合框项目,则即使第一个异步请求返回,SelectionChanged事件也可能会多次触发(生成多个异步请求)。这会从组合框的SelectionChanged事件称为持续取消Async CancellationTokenSource的最佳实践

所以我的异步函数如下所示:

public async Task<Connections> ConnectionsAsync() 
{ 
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token); 
} 

如果连接的是,熄灭并点击了Web服务的属性。所以,因为CancellationTokenSource不能重复使用,一旦取消,我想这样做的:

public async Task<Connections> ConnectionsAsync() 
{ 
    _cancellationTokenSource.Cancel(); 
    _cancellationTokenSource = new CancellationTokenSource(); 
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token); 
} 

的问题是,虽然有时候我会打电话取消()时,有没有运行的异步命令(例如第一次这个函数被调用);所以如果我连接任何取消事件处理程序,他们将被调用,甚至在我做出异步请求之前。

无论如何检查一个异步请求是否已经在运行?除了我做这样的事情:

public async Task<Connections> ConnectionsAsync() 
{ 
    if (_runningAsyncCommand) 
     _cancellationTokenSource.Cancel(); 
    _cancellationTokenSource = new CancellationTokenSource(); 
    _runningAsyncCommand = true; 
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token); 
    _runningAsyncCommand = false; 
} 

我有全部使用相同CancellationTokenSource一些异步函数,所以我就必须实现所有这些功能这个“管道”。这是最好的方法吗?或者,还有更好的方法?

另外,如果我公开地公开_cancellationTokenSource,以便其他类可以使用它注册取消委托,那么将这些委托“转移”到新的CancellationTokenSource的最佳方法是什么,因为我每次都创建一个新的CancellationTokenSource?

在此先感谢!

+0

它解决了吗?我现在有完全相同的问题。 – 2012-08-14 04:57:38

+0

不,它没有解决,但现在回顾我的问题,我认为正确的做法是将CancellationTokenSource的令牌作为可选参数(即公共异步任务 ConnectionsAsync(CancellationToken token = null))。这样用户调用ConnectionsAsync()函数负责设置一个新的CancellationTokenSource并传递它的Token。 – deadlydog 2012-08-14 16:35:52

+0

所以在我的例子中,这会发生在我的ComboBox的SelectionChanged事件中;我将在现有的CancellationTokenSource上调用Cancel(),创建一个新的,并将其Token传递给ConnectionsAsync()函数。最后,尽管对于我的特定应用程序,我最终没有使用取消。 – deadlydog 2012-08-14 16:45:28

回答

2

看起来像在天堂里为反应性扩展所做的配对。定义必须经过节流时间(比方说300毫秒)观察从ComboBox的事件时创建的任务

代码之前代码段订阅文本框更改事件,但你会得到的想法:

var input (from evt in Observable.FromEvent<EventArgs>(txt, "TextChanged") 
select ((TextBox)evt.Sender).Text) 
.Throttle(TimeSpan.FromSeconds(1)) 
.DistinctUntilChanged(); 

using (input.Subscribe(inp => Console.WriteLine("You wrote: " + inp))) 
{ 
    // Do stuff 
} 
+0

一个不错的解决方案,但仍不完美。假设我对Web服务的请求需要3秒钟才能返回。用户可能仍然每2秒更换一次组合框选择,在这种情况下,我仍然有同样的问题。 我不想将油门设置得太高,例如2秒,否则每次改变选择时都会有2秒的延迟,然后它才发送请求;因此从更改选择到UI更新的时间总共需要5秒。 – deadlydog 2012-07-07 19:36:38

+0

您是否考虑实施(预先加载的)本地缓存机制?您是否真的需要从组合框更改选择中检索实时数据? – 2012-07-07 20:38:26

+0

我*可能*能够为我的特定情况缓存数据,因为只有大约75个人可以更改我正在检索的数据。原来的问题仍然有效,假设我的组合框列出了我的Twitter帐户,当我选择一个帐户时,我想查看该帐户的实时供稿。这是一个完美的例子,您总是需要实时数据。 – deadlydog 2012-07-08 04:57:10