反应式扩展-中止/取消OnCompleted



我有一个显示状态消息的控件;控件在一段时间后隐藏。这是处理它的代码:

private void ShowFor(TimeSpan? delay)
{
   Visible = true;
   if (!delay.HasValue) return; 
  // _pauseTimer is a MultipleAssignmentDisposable
  _pauseTimer.Disposable = Observable
     .Timer(delay.Value)
     .ObserveOn(SynchronizationContext.Current)
     .Subscribe(
          onNext:  _ => { /* do nothing */ },
     onCompleted: () => { Visible = false; },
         onError:  e => { /* what could possibly go wrong? */});
}

显示控制,等待n秒,隐藏控制。很简单。

问题是,当在该计时器结束之前收到另一条消息时,该怎么办。第二条消息显示,然后第一个计时器过期并提前隐藏控件。

如何"中止"上一个计时器?处理pauseTimer.Disposable

_pauseTimer更改为SerialDisposable而不是MultipleAssignmentDisposable,然后每次执行_pauseTimer.Disposable = newDisposable时,它都会丢弃当前订阅,以便订阅下一个。

您可以将显示控件与隐藏控件区分开来。假设消息来自IObservable<string> messages(如果当前不是,则很容易设置(,那么订阅它并将控件设置为在OnNext中与消息一起可见。

另外,订阅相同的流,并应用一个节流阀,以在您需要多长时间后隐藏消息,例如:

messages.Throttle(TimeSpan.FromSeconds(1))
        .ObserveOn(SynchronizationContext.Current)
        .Subscribe(_ => control.Visible = false);

只有在没有看到所需延迟的新消息时,油门才会发出。

为了解释不同的延迟,请将消息源设置为包装消息和严重性的类型。为了简单起见,我将使用Tuple<string, Timespan>,但您可以使用枚举来表示严重性,并进行更详细的操作。Throttle有一个过载,它通过任何流来改变它的持续时间。您可以根据消息持续时间创建Throttle源:

// assuming messages is `Tuple<string, Timespan>`
var delayStream = messages.Throttle(
    messages.SelectMany(x => Observable.Timer(x.Item2)))

这将根据消息的严重性创建不同的限制,并且您可以对严重警告使用非常大的(最大(超时,或者只为它们发出Observable.Empty,而不使用计时器。

请注意,在此方案下(以及使用单个控件的描述(,新消息将替换以前的消息。一个小的更改将使其易于处理——如果您的控件显示多条消息,并且每条消息都带有一个id,则可以使用delayStream来决定需要从当前列表中删除哪条消息。

相关内容

  • 没有找到相关文章

最新更新