Dato un fonte osservabile, generato mediante il polling (variazioni di a) stato di un dispositivo di basso livello ...Rx quadro: eseguire un'azione su timeout senza interrompere la sequenza originale osservabile
// observable source metacode:
IObservable<DeviceState> source = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Select(tick => new DeviceState(_device.ReadValue()))
.DistinctUntilChanged();
.. . e un consumatore che aggiorna l'interfaccia utente ...
// UI metacode:
service.GetObservableDeviceStates()
.Subscribe(state => viewModel.CurrentState = state.ToString());
... ho bisogno di eseguire un'azione personalizzata dopo x secondi di "inattività" della fonte, senza interrompere l'abbonamento alla sorgente. Qualcosa del genere:
// UI metacode:
service.GetObservableDeviceStates()
.DoOnTimeout(TimeSpan.FromSeconds(x),() => viewModel.CurrentState = "Idle")
.Subscribe(state => viewModel.CurrentState = state.ToString());
Quali sono le migliori pratiche? Possibili soluzioni che vengono in mente sono (io sono un noob Rx):
- Buffer (anche se non è così leggibile)
- Giocando intorno this Timeout overload;
Tornando qualcosa di speciale "service-side", quando nulla cambia (invece di utilizzare DistinctUntilChanged) e trattare con esso sul codice utente:
service.GetObservableDeviceStates() .Iscriviti (Stato => viewModel.CurrentState = state.Special? "Idle": state.ToString());
EDIT: come riportato in the answer, la soluzione è:
service.GetObservableDeviceStates()
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.Subscribe(onTimeout);
EDIT2 (Warning)
Se i componenti aggiornamenti dell'interfaccia utente onNext e onTimeout, per evitare CrossThreadExceptions due ObserveOn (uiSynchronizationContext) sono necessari, dal momento che Throttle funziona su un altro thread!
service.GetObservableDeviceStates()
.ObserveOn(uiSynchronizationContext)
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.ObserveOn(uiSynchronizationContext)
.Subscribe(onTimeout);
È possibile specificare lo scheduler thread UI come parametro a manetta, al fine di eseguire i timer di limitazione lì, in caso si vuole evitare l'hop ObserveOn aggiuntivo. –
@BartDeSmet Ho già provato Throttle (x, Scheduler.CurrentThread), ma stavo perdendo la reattività dell'interfaccia utente ... Nel mio caso, ObserveOn ha funzionato meglio – Notoriousxl