2015-08-20 27 views
1

我有一个显示状态消息的控件;该控件在间隔后隐藏。这里是处理它的代码:无效扩展 - 中止/取消完成

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? */}); 
} 

显示控制,等待ñ秒,隐藏控制。十分简单。

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

如何“中止”前一个计时器?处置pauseTimer.Disposable

回答

1

你可以单独显示控件隐藏它。假设这些消息来自IObservable<string> messages(如果它们当前不是这样,则可以很容易地设置它),然后订阅此消息并将消息设置为OnNext中的消息。

另外,订阅与节流相同的流应用到隐藏你需要经过多么漫长的消息,例如:

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

油门只会发出当有新邮件已经不明显了期望的延迟。

为了解决各种延迟问题,请将您的消息源作为包装消息和严重性的类型。为了简单起见,我将使用Tuple<string, Timespan>,但您可以使用枚举来表示严重性并执行更详细的操作。油门有一个过载可以改变任何流的持续时间。您可以创建基于消息持续时间油门来源:

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

这将创建一个不同的油门基于消息的严重程度,你可以使用一个非常大的(最大)超时严重警告 - 或者只是发出Observable.Empty为他们而不是使用计时器。

请注意,根据此方案(以及您的描述使用单个控件),新消息将替换之前的消息。如果您的控件显示多条消息并且每个消息都带有一个ID,则可以使用delayStream来决定从当前列表中删除哪一个。

+0

我甚至从来没有想过让消息成为一个序列本身;非常聪明。我看到的唯一问题是,消息会因严重程度而异,而且并不都显示相同的时间量 - 有些则需要手动解散。你会如何弥补? –

+0

编辑以反映您的意见,并处理不同的严重程度。 –

2

变化_pauseTimerSerialDisposable而非MultipleAssignmentDisposable,然后每次你做_pauseTimer.Disposable = newDisposable时,它将出售其目前的订阅是订阅下。