I'm using reactive extensions in my wp7 app that I'm making and I wish to get the the current location at certain intervals (intervals are based on a user setting). For this example lets say after every 5 seconds I wish to know the current location from the GeoCoordinateWatcher.
I have read some places that I can use .Delay(5 Seconds) but wouldn't that just delay the stream of position changes? As I am only after the current position, would .Delay(5 seconds).Last() work for what I want?
My code so far
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();
I'm thinking something like this would work?
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: Nope it doesn't work
There are a few different rate limiting operators in RX. Sample
is the closest to what you describe, but it will not generate a notification every 5 seconds if the source is not producing new notifications (in other words: Sample = "no more often than").
You should be able to get a polling effect by combining a few other operators. To start, we will need Interval
to get the ticks and CombineLatest
to do the sampling at the ticks. However, CombineLatest will output a result both on ticks and notifications from the original source. To deal with that, we can use a combination of Scan
, Where
and Select
. In the end you should have something like:
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);
}
A few notes about the code you posted:
var pos = (from s in status
from p in Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(LocationServices, "PositionChanged")
select p.EventArgs.Position);
This makes a new subscription to the PositionChanged
event every time the status event is triggered as ready. This will eventually cause position changes to be reported multiple times, which is probably not what you want. You probably want something more like:
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 Upon further review, if all you want to do is poll the position every so often, there is no need to handle either event. You can simply check the properties on a timer.
var readyPositions = from tick in Observable.Interval(TimeSpan.FromSeconds(5))
where LocationServices.Status == GeoPositionStatus.Ready
select LocationServices.Position;
If you only want the timer to run while the watcher is "Ready", you can use the status event, but still don't need to use the position event.
//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;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.