Получить текущее местоположение после интервала, используя RX - PullRequest
0 голосов
/ 07 марта 2012

Я использую реактивные расширения в своем приложении wp7, которое я делаю, и я хочу получить текущее местоположение через определенные интервалы (интервалы основаны на пользовательских настройках) Для этого примера, скажем, каждые 5 секунд я хочу узнать текущее местоположение из GeoCoordinateWatcher.

Я прочитал некоторые места, которые я могу использовать .Delay (5 секунд), но разве это не задержит поток изменений позиции? Как и после текущей позиции, .Delay (5 секунд) .Last () будет работать для того, что я хочу?

Мой код пока что

if (LocationServices == null)
     LocationServices = new GeoCoordinateWatcher(GeoPositionAccuracy.High)
     {
        MovementThreshold = 2
     };

// Take the first ready status from the GeoCoordinateWatcher
var status = (from o in Observable.FromEvent<GeoPositionStatusChangedEventArgs>                  LocationServices, "StatusChanged")
              where o.EventArgs.Status == GeoPositionStatus.Ready
              select o);

status.Subscribe();

var pos = (from s in status
           from p in Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(LocationServices, "PositionChanged")
           select p.EventArgs.Position); // Do something here to delay?

        pos.Subscribe(LastPos =>
        {
            // Do something with LastPos
        }
        );

        LocationServices.Start();

Я думаю, что-то подобное будет работать?

var pos = (from s in status
           from p in Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(LocationServices, "PositionChanged")
           select p.EventArgs.Position).Delay( var pos = (from s in status
                   from p in Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(LocationServices, "PositionChanged")
                   select p.EventArgs.Position).TakeLast(1).Delay(new TimeSpan(0,0,5));

        pos.Subscribe(Lastpos =>
        {
           // Do something with Lastpos 
        }
        );;           

Редактировать: Нет, это не работает

1 Ответ

2 голосов
/ 07 марта 2012

В 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;
...