所以我调用Dispatcher.BeginInvoke()
来在Timer.Elapsed
事件中执行一些UI操作。计时器正在快速计时,在前一个调用被完全处理之前,BeginInvoke()
的多个新实例可能会堆积起来。在处理完当前调用后,我总是只想选择BeginInvoke()
的最新实例,即消息队列上任何以前未处理的实例都应该被丢弃。
清空Dispatcher的BeginInvoke队列以实现此目的的正确方法是什么?
为了演示一个示例,请考虑我每秒几次从Timer.Elapsed事件中的传感器读取值,然后更新复杂的UI以显示读取的值。此UI更新操作需要一些时间,在此期间,一个或多个读取值的新实例会堆积在调度程序队列上进行渲染。显然,当我从传感器获得更新的值时,我想丢弃等待行中的所有实例,只保留当前实例,以便在处理器空闲时发送渲染。
由于您没有管理UI线程,因此没有机会对回调进行出列。但您可以使用CancellationTokenSource:
-
传递CancellationTokenSource(CancellationTokensSource.Token)发送到调度程序和您的回调。
-
通过在回调中重复调用CancellationToken.SthrowIfCancellationRequested()来侦听取消,并捕获CancellationTokensSource.Cancel()调用后将抛出的OperationCanceledException异常
-
使用catch块捕获OperationCanceledException并进行清理,以便将状态反转为执行回调之前的状态
-
在用新操作调用调度程序之前,您可以通过调用CancellationTokenSource.cancel()来取消所有以前的回调。这将触发ThrowIfCancellationRequested()在回调中实际抛出OperationCanceledException。
-
从一个新的CancellationTokenSource实例中调用具有新回调和新CancellationToken的调度程序,并处理所有已取消的取消TokenSource实例。
通过这种方式,您可以取消调度程序操作,例如在长时间运行的情况下,或者在操作仍然挂起的情况下阻止执行该操作。否则,您必须将下一个调度程序操作排入队列,并覆盖上一个操作的更改。
Dispatcher.InvokeAsync(…)等于Dispatchher.BeginInvoke(…)[/em>,但它还允许您向调度程序传递取消令牌。