Dada una fuente observable, generada mediante el sondeo de los cambios (a) estado de un dispositivo de bajo nivel ...Rx Marco: ejecutar una acción en tiempo de espera sin interrumpir la secuencia original, observable
// observable source metacode:
IObservable<DeviceState> source = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Select(tick => new DeviceState(_device.ReadValue()))
.DistinctUntilChanged();
.. . y un consumidor que actualiza la interfaz de usuario ...
// UI metacode:
service.GetObservableDeviceStates()
.Subscribe(state => viewModel.CurrentState = state.ToString());
... necesito para ejecutar una acción personalizada después de x segundos de "inactividad" de la fuente, sin interrumpir la suscripción a la fuente. Algo como esto:
// UI metacode:
service.GetObservableDeviceStates()
.DoOnTimeout(TimeSpan.FromSeconds(x),() => viewModel.CurrentState = "Idle")
.Subscribe(state => viewModel.CurrentState = state.ToString());
¿Cuáles son las mejores prácticas? Las posibles soluciones que vienen a la mente son (soy un novato Rx):
- Buffer (aunque no es tan legible)
- Jugando this Timeout overload;
Volviendo algo especial "del lado del servicio" cuando nada cambia (en lugar de utilizar DistinctUntilChanged) y tratar con ella en el código de interfaz de usuario:
service.GetObservableDeviceStates() .Subscribe (estado => viewModel.CurrentState = state.Special? "Idle": state.ToString());
EDIT: como se informó in the answer, la solución es:
service.GetObservableDeviceStates()
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.Subscribe(onTimeout);
Edit2 (advertencia)
Si los componentes actualizaciones de interfaz de usuario onNext y onTimeout, para evitar CrossThreadExceptions dos ObserveOn (uiSynchronizationContext) son necesarios, ya que Throttle trabaja en otro hilo.
service.GetObservableDeviceStates()
.ObserveOn(uiSynchronizationContext)
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.ObserveOn(uiSynchronizationContext)
.Subscribe(onTimeout);
puede especificar el programador de subprocesos de interfaz de usuario como parámetro al acelerador con el fin de ejecutar los temporizadores de estrangulación allí, en caso de que quiera evitar el salto ObserveOn adicional. –
@BartDeSmet Ya probé Throttle (x, Scheduler.CurrentThread), pero estaba perdiendo la capacidad de respuesta de la interfaz de usuario ... En mi caso, ObserveOn funcionó mejor – Notoriousxl