所以我正在调用Dispatcher.BeginInvoke()
在Timer.Elapsed
事件中执行一些UI操作。计时器快速滴答,BeginInvoke()
的多个新实例可能在完全处理前一个呼叫之前堆叠起来。在完成当前调用的处理之后,我总是对选择BeginInvoke()
的最新实例感兴趣,即应该丢弃消息队列中任何以前未处理的实例。
清空Dispatcher的BeginInvoke队列以实现此目的的正确方法是什么?
为了演示一个例子,考虑我每秒钟从Timer.Elapsed事件中的传感器读取数值,然后更新复杂的UI以显示读取值。此UI更新操作需要一些时间,在此期间,读取值的一个或多个新实例将堆叠在调度程序队列上以进行呈现。显然,当我从传感器获得更多近期值时,我想要丢弃等待线中的所有实例,并且只保留当前的实例,一旦处理器空闲,就将其发送给渲染。
答案 0 :(得分:2)
由于您没有管理UI线程,因此没有机会将回调出列。 但您可以使用CancellationTokenSource:
传递CancellationTokenSource(CancellationTokenSource.Token) 调度员和你的回调。
通过在回调中反复调用CancellationToken.ThrowIfCancellationRequested()来监听取消,并捕获在调用CancellationTokenSource.Cancel()后将抛出的 OperationCanceledException 异常
< / LI>使用catch块来捕获 OperationCanceledException 并进行清理以便将状态反转为执行回调之前
在使用新操作调用调度程序之前,您可以通过调用CancellationTokenSource.Cancel()来取消之前的所有回调。这将触发ThrowIfCancellationRequested()在回调中实际抛出 OperationCanceledException 。
从新的 CancellationTokenSource 实例调用带有新回调和新 CancellationToken 的调度程序,并处置所有已取消的 CancellationTokenSource 实例。
这样您可以取消调度程序操作,例如如果它长时间运行或阻止它被执行以防行动仍未决定。否则,您必须将下一个调度程序操作排入队列并覆盖上一个操作的更改。
Dispatcher.InvokeAsync(...)等于 Dispatchher.BeginInvoke(...),但此外它还允许您将取消令牌传递给调度程序