【问题标题】:await too slow for frequent events; can async methods ignore cancellations?await 对于频繁的事件来说太慢了;异步方法可以忽略取消吗?
【发布时间】:2015-12-24 06:58:17
【问题描述】:

我有一个需要对SizeChanged 事件做出反应的 WPF 窗口。但是,它应该仅在 500 毫秒内没有进一步的 SizeChanged 事件时执行处理(类似于 BindingBase.Delay 提供的行为)。

private CancellationTokenSource lastCts;

private async void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (lastCts != null)
        lastCts.Cancel();
    lastCts = new CancellationTokenSource();

    try
    {
        await Task.Delay(500, lastCts.Token);
    }
    catch (OperationCanceledException)
    {
        return;
    }

    myTextBox.Text = string.Format("({0}, {1})", this.Width, this.Height);            
}

但是,我注意到,在调试模式下编译为 x64 时,此代码会导致 UI 在调整大小时开始滞后;重绘窗口有明显的延迟。我认为这是由于OperationCanceledException 在 UI 线程上被序列化、抛出和捕获。下面的代码消除了这个问题:

    Task.Delay(500, lastCts.Token).ContinueWith(
        _ =>
        {
            myTextBox.Text = string.Format("({0},{1})", this.Width, this.Height);
        },
        lastCts.Token,
        TaskContinuationOptions.NotOnCanceled,
        TaskScheduler.FromCurrentSynchronizationContext());

我的问题是:如果未取消等待的任务,是否有一种干净的方法可以配置异步方法以仅在 UI 线程上恢复处理?或者这是边界情况之一,由于SizeChanged 事件的频率,我们不应该使用等待,而是恢复到提供更多控制的旧ContinueWith 模式(如TaskContinuationOptions.NotOnCanceled)?

【问题讨论】:

  • 检查this。您可以从那里以非常相似的方式使用AsyncOp

标签: c# .net wpf async-await


【解决方案1】:

它应该只在 500 毫秒内没有进一步的 SizeChanged 事件时才执行处理

只要您有“时间”要求,这就是您应该使用Rx 的一个非常明确的信号。这样的事情应该可以工作:

Observable.FromEventPattern<SizeChangedEventHandler, SizeChangedEventArgs>(h => SizeChanged += h, h => SizeChanged -= h)
    .Throttle(TimeSpan.FromMilliseconds(500))
    .ObserveOn(SynchronizationContext.Current)
    .Subscribe(_ =>
    {
       myTextBox.Text = string.Format("({0}, {1})", this.Width, this.Height);
    });

【讨论】:

猜你喜欢
  • 2012-06-16
  • 2020-08-08
  • 2017-11-26
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多