В RX есть несколько разных операторов ограничения скорости.Sample
является наиболее близким к тому, что вы описываете, но оно не будет генерировать уведомление каждые 5 секунд, если источник не генерирует новые уведомления (другими словами: Sample = "не чаще, чем").
Вы должны быть в состоянии получить эффект опроса, комбинируя несколько других операторов.Для начала нам понадобится Interval
, чтобы получить тики, и CombineLatest
, чтобы сделать выборку по тикам.Однако CombineLatest будет выводить результат как по тикам, так и по уведомлениям из исходного источника.Чтобы справиться с этим, мы можем использовать комбинацию Scan
, Where
и Select
.В конце у вас должно получиться что-то вроде:
IObservable<T> Poll<T>(this IObservable<T> source, TimeSpan interval)
{
//error checking goes here
return source.CombineLatest(Observable.Interval(interval),
Tuple.Create)
.Scan(Tuple.Create(string.Empty, -1L, -1L),
(a, t) => Tuple.Create(t.Item1, t.Item2, a.Item2))
.Where(t => t.Item2 != t.Item3)
.Select(t => t.Item1);
}
Несколько замечаний о коде, который вы разместили:
var pos = (from s in status
from p in Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(LocationServices, "PositionChanged")
select p.EventArgs.Position);
Это делает новую подписку на событие PositionChanged
каждый раз, когдаСобытие статуса запускается как готовое.Это в конечном итоге приведет к тому, что об изменениях положения будут сообщаться несколько раз, что, вероятно, не то, что вам нужно.Вы, вероятно, хотите что-то более похожее на:
var status = Observable.FromEvent<...>(LocationServices, "StatusChanged");
var readys = status.Where(o => o.EventArgs.Status == GeoPositionStatus.Ready);
var notReadys = status.Where(o => o.EventArgs.Status != GeoPositionStatus.Ready);
var positions = Observable.FromEvent<...>)(LocationServices, "PositionChanged");
var readyPositions = from r in readys
from p in positions.TakeUntil(notReadys)
select p;
//now you can use the Poll operator
readyPositions = readyPositions.Poll(TimeSpan.FromSeconds(5));
РЕДАКТИРОВАТЬ При дальнейшем рассмотрении, если все, что вы хотите сделать, это периодически опрашивать позицию, нет необходимости обрабатывать любое событие.Вы можете просто проверить свойства таймера.
var readyPositions = from tick in Observable.Interval(TimeSpan.FromSeconds(5))
where LocationServices.Status == GeoPositionStatus.Ready
select LocationServices.Position;
Если вы хотите, чтобы таймер работал только тогда, когда наблюдатель находится в состоянии «Готов», вы можете использовать событие состояния, но все же не нужно его использоватьПоложение события.
//using variable definitions from above (readys, notReadys)
var readyPositions = from r in readys
from i in Observable.Interval(TimeSpan.FromSeconds(5))
.TakeUnitl(notReadys)
select LocationServices.Position;