2015-08-20 26 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時,它將出售其目前的訂閱是訂閱下。