2012-03-07 2 views
0

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

Я прочитал несколько мест, которые я могу использовать. Delay (5 Seconds), но разве это не просто задерживает поток изменений позиции? Поскольку я только после текущей позиции, будет. Отложить (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 
     } 
     );;   

Edit: неа не работает

ответ

2

Есть несколько различных операторов ограничение скорости в 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)); 

EDIT После дальнейшего рассмотрения, если все, что вам нужно сделать, это опрашивать позицию так часто, нет необходимости обрабатывать либо события. Вы можете просто проверить свойства на таймере.

var readyPositions = from tick in Observable.Interval(TimeSpan.FromSeconds(5)) 
        where LocationServices.Status == GeoPositionStatus.Ready 
        select LocationServices.Position; 

Если вы хотите таймер для запуска в то время как наблюдатель является «Ready», вы можете использовать событие состояния, но все-таки не нужно использовать событие позиции.

//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; 
+0

Ницца! спасибо за это, я буду пристально смотреть, когда я получу сегодня вечером и посмотрю, смогу ли я заставить его работать. Отчитается с результатом – Gaz83

+0

Как вы остановите все это, как только вы избавитесь от GeoCoordinateWatcher (LocationServices)? – Gaz83

+0

@ Gaz83 Статус может переключиться на NoData, и в этом случае вы можете следить за этим. В противном случае вам придется иметь доступ к тому, чтобы распоряжаться наблюдателем. –

Смежные вопросы