For some reason I find myself doing some Windows Phone 8.1 development in Silverlight.. I know its a dead end and all the rest but I am working on a small app and Silverlight API was more mature at least for Windows Phone 8.1. One of the things I was adding was GeoFencing. GeoFencing was introduced to Windows Phone 8.1 WinRT API and some of it was exposed to Silverlight API (whoever made the decision on what APIs were available in WinRT and what in Silverlight needs to be shot.. at least made to feel real pain.
The way you set it up is you create GeoFence instances and add them.. System managed associated with your app. The app can access it from foreground or background.. nice right ? The constructor for GeoFence states that it requires IGeoshape along with an identifier at the very least.. IGeoshape is an enum which has possible values of Point, Circle, BoundingBox and Path. The constructor for GeoFence explicitly states now and again that the IGeoshape has to be a valid GeoCircle.. I know documentation can be wrong.. I mean why would you go through the hassle of create an Interface and passing it again if you enforce explicit type ?
I was wrong.. I tried it both the Silverlight and through WinRT API.. nope documentation is correct.. the API though designed well has shite implementation 😐 So what next ?
Well DIY. Here is my implementation.. Create a Rect instance with NorthWest X1, Y1 and SouthEast and X2 Y2 and monitor the change in geo position. Check if the new point is within Rect or not.. easy peasy.. well it works too.. Here is my implementation.
public class GeoMonitoringService { Geolocator _locator = null; Dictionary<GeoSite, Rect> _locationRectangles = null; DataService _dataService = null; public event RoutedPropertyChangedEventHandler<GeomonitorStateChangedEventArgs> GeomonitorStateChanged; public bool lastState = false; public void Initialise(DataService dataService) { _locator = new Geolocator(); _locator.DesiredAccuracy = PositionAccuracy.High; _locator.MovementThreshold = 1; _locator.ReportInterval = Convert.ToUInt32(TimeSpan.FromSeconds(5).TotalMilliseconds); this._locationRectangles = new Dictionary<GeoSite, Rect>(); this._dataService = dataService; if (this._dataService?.SiteDictionary?.Count > 0) { foreach (var site in this._dataService.SiteDictionary.Values) { Rect r = new Rect(new Point(site.Latitude1, site.Longitude1), new Point(site.Latitude2, site.Longitude2)); this._locationRectangles.Add(site, r); } } _locator.PositionChanged += GPSPositionChanged; } private void GPSPositionChanged(Geolocator sender, PositionChangedEventArgs args) { var geoPoint = args.Position.Coordinate.Point; Point p = new Point(geoPoint.Position.Latitude, geoPoint.Position.Longitude); KeyValuePair<GeoSite, Rect>? matchKVP = null; foreach (var entry in this._locationRectangles) { if (entry.Value.Contains(p)) { matchKVP = entry; break; } } if (matchKVP.HasValue) { if (!lastState) { lastState = true; this.GeomonitorStateChanged?.Invoke(this, new RoutedPropertyChangedEventArgs<GeomonitorStateChangedEventArgs>(null, new GeomonitorStateChangedEventArgs(true, matchKVP.Value.Key))); } } else { if (lastState) { lastState = false; this.GeomonitorStateChanged?.Invoke(this, new RoutedPropertyChangedEventArgs<GeomonitorStateChangedEventArgs>(null, new GeomonitorStateChangedEventArgs(false, null))); } } } }