BeginInvoke调用的同步



所以我调用Dispatcher.BeginInvoke()来在Timer.Elapsed事件中执行一些UI操作。计时器正在快速计时,在前一个调用被完全处理之前,BeginInvoke()的多个新实例可能会堆积起来。在处理完当前调用后,我总是只想选择BeginInvoke()的最新实例,即消息队列上任何以前未处理的实例都应该被丢弃。

清空Dispatcher的BeginInvoke队列以实现此目的的正确方法是什么?

为了演示一个示例,请考虑我每秒几次从Timer.Elapsed事件中的传感器读取值,然后更新复杂的UI以显示读取的值。此UI更新操作需要一些时间,在此期间,一个或多个读取值的新实例会堆积在调度程序队列上进行渲染。显然,当我从传感器获得更新的值时,我想丢弃等待行中的所有实例,只保留当前实例,以便在处理器空闲时发送渲染。

由于您没有管理UI线程,因此没有机会对回调进行出列。但您可以使用CancellationTokenSource:

  1. 传递CancellationTokenSource(CancellationTokensSource.Token)发送到调度程序和您的回调。

  2. 通过在回调中重复调用CancellationToken.SthrowIfCancellationRequested()来侦听取消,并捕获CancellationTokensSource.Cancel()调用后将抛出的OperationCanceledException异常

  3. 使用catch块捕获OperationCanceledException并进行清理,以便将状态反转为执行回调之前的状态

  4. 在用新操作调用调度程序之前,您可以通过调用CancellationTokenSource.cancel()来取消所有以前的回调。这将触发ThrowIfCancellationRequested()在回调中实际抛出OperationCanceledException

  5. 从一个新的CancellationTokenSource实例中调用具有新回调和新CancellationToken的调度程序,并处理所有已取消的取消TokenSource实例。

通过这种方式,您可以取消调度程序操作,例如在长时间运行的情况下,或者在操作仍然挂起的情况下阻止执行该操作。否则,您必须将下一个调度程序操作排入队列,并覆盖上一个操作的更改。

Dispatcher.InvokeAsync(…)等于Dispatchher.BeginInvoke(…)[/em>,但它还允许您向调度程序传递取消令牌。

最新更新