低レベルデバイスの状態(の変化)をポーリングすることによって生成された、観測可能なソースが与えられます。
// observable source metacode:
IObservable<DeviceState> source = Observable.Interval(TimeSpan.FromSeconds(0.5))
.Select(tick => new DeviceState(_device.ReadValue()))
.DistinctUntilChanged();
...そしてUIを更新するコンシューマー...
// UI metacode:
service.GetObservableDeviceStates()
.Subscribe(state => viewModel.CurrentState = state.ToString());
...ソースへのサブスクリプションを中断せずに、ソースの「非アクティブ」のx秒後にカスタムアクションを実行する必要があります。このようなもの:
// UI metacode:
service.GetObservableDeviceStates()
.DoOnTimeout(TimeSpan.FromSeconds(x), () => viewModel.CurrentState = "Idle")
.Subscribe(state => viewModel.CurrentState = state.ToString());
ベストプラクティスは何ですか?頭に浮かぶ考えられる解決策は次のとおりです(私はRx noobです):
- バッファ(それほど読みにくい場合でも)
- このタイムアウトの過負荷を回避します;
(DistinctUntilChangedを使用する代わりに)何も変更されていないときに特別な「サービス側」を返し、UIコードで処理します。
service.GetObservableDeviceStates().Subscribe(state => viewModel.CurrentState = state.Special? "Idle":state.ToString());
編集:答えで報告されているように、解決策は次のとおりです:
service.GetObservableDeviceStates()
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.Subscribe(onTimeout);
EDIT2(警告)
onNextとonTimeoutがUIコンポーネントを更新する場合、CrossThreadExceptionsを回避するには、Throttleが別のスレッドで動作するため、 2つのObserveOn(uiSynchronizationContext)が必要です。
service.GetObservableDeviceStates()
.ObserveOn(uiSynchronizationContext)
.Do(onNext)
.Throttle(TimeSpan.FromSeconds(x))
.ObserveOn(uiSynchronizationContext)
.Subscribe(onTimeout);