如何在C#或类似框架中按顺序运行事件

时间:2014-04-15 13:02:15

标签: c# multithreading events

如何在另一个线程中取消/调整与同一事件并行执行的事件。

例如在文本框中,每次输入字符时,如果定义了文本更改事件,则事件将触发。但是在输入第一个字符后,事件(让我们称之为第一个事件)需要花费很多时间(因为会有更多字符串与单个字符匹配),并且会执行一些操作,例如更改标题标签的内容。输入第二个字符后,并行运行的新事件花费的时间更少。所以现在,在输入第二个字符后触发的第二个事件快速执行并返回第一个事件并且第一个事件最后执行,因此,第一个事件的结果将最终打印在标签上而不是第二个上。

在开始第二个事件之前,是否有更好的方法取消第一个事件。我想到的一件事是在全局列表变量上注册线程,并在开始执行之前终止所有未死的线程。这会有用吗?任何更好的方法来处理这种情况。

P.S。我知道搜索可以在空格之后启动或输入以解决此特定问题。但我想你已经注意到了我的要点。 :)

2 个答案:

答案 0 :(得分:1)

.NET Task API具有内置取消的概念。请参阅此页面以获取示例并链接到更多信息。 http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

答案 1 :(得分:1)

我最喜欢的处理此问题的库是Rx.Net TPL。使用Observable.FromAsync

将可取消任务与事件观察者相结合,可以轻松实现此行为

一些代码!

var textChanged = Observable.FromEventPattern(x => textBox.TextChanged += x, x => textBox.TextChanged -= x)
                        .Select(_ => textBox.Text);
IDisposable eventHandler = textChanged.Throttle(TimeSpan.FromMilliseconds(500))
                              .Select(text => Observable.FromAsync((TaskCancelationToken cancel) => DoSearchTaskAsync(text, cancel)))
                              .Switch()
                              .Subscrible(results =>
                              {
                                  //Update the UI
                              });

请注意,没有必要明确键入任何内容......我只是为了清晰起见,但我很可能错误地输入了一两个类名......

修改

搜索方法将是Task<TReturn> DoSearchTaskAsync(string, TaskCancellationToken)的方法主体。

魔法酱来自Observable.FromAsyncObservable.Switch

每次我们对textBox.Text进行更改时,我们都会触发一个事件。这是由.Throttle过滤的(如您所料)。聪明的一点就是当我们使用DoSearchTaskAsyncObservable.FromAsync上创建新的事件源时。在这一点上,我们有一个IObservable<IObservable<TResult>>或其他方式来放置它,一个事件源的事件源。切换意味着我们只需要来自outter eventsource的最近发送的eventsource的结果,并且kill(Dispose)以前的eventsources的订阅。

处理上一个Observable.FromAsync的行为将导致TaskCancellationToken取消,并防止其结果冒泡,同时我们订阅新的Task

所有非常聪明的东西,我最近才遇到过这种令人敬畏的模式(如果可能,我会相信作者)。

至于非常不幸的Observable.FromEventPattern,从C#5开始,没有一流的事件处理程序,所以我们传入一个lambda用于订阅,一个lambda用于取消订阅。