Wednesday, September 26, 2018

GeoCoordinateWatcher and GMap.NET

Playing around a little with the GMap.NET - Maps For Windows and figured I would use my computers location as a startup point for the map view.
Ended up encapsulating System.Device.Location.GeoCoordinateWatcher in a static class to get around the NaN coordinates returned from an uninitialized GeoCoordinateWatcher as it turns out that GMap.NET doesn't like NaN at all.
using System.Device.Location;

namespace dreamstatecoding.blogspot.com
{
    public static class GeoProvider
    {
        private static GeoCoordinateWatcher _watcher = new GeoCoordinateWatcher();
        public static bool IsInitialized { get; private set; }

        static GeoProvider()
        {
            _watcher.PositionChanged += _watcher_PositionChanged;
            _watcher.Start();
        }
        public static void Cleanup()
        {
            _watcher.Stop();
            _watcher.Dispose();
            _watcher = null;
        }
        private static void _watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            IsInitialized = true; ;
        }

        public static GeoCoordinate GetCoordinates()
        {
            var coordinates = _watcher.Position.Location;
            if (double.IsNaN(coordinates.Latitude))
                return new GeoCoordinate(0, 0);
            return coordinates;
        }
    }
}

Usage: Giving the provider some time to get hold of the first coordinates. If it doesn't, the coordinate returned would be longitude:0;latitude:0. So pretty much in the ocean outside of Africa.
private void SetupMap()
{  
 for(int i = 0; i < 1000; i++)
 {
  if (GeoProvider.IsInitialized)
   break;
  Thread.Sleep(151);
 }
 var coordinates = GeoProvider.GetCoordinates();
 gmap.MapProvider = GMapProviders.GoogleMap;
 gmap.Position = new PointLatLng(coordinates.Latitude, coordinates.Longitude);
 gmap.MinZoom = 0;
 gmap.MaxZoom = 24;
 gmap.Zoom = 15;
}

It seems that the thread in the GeoCoordinateWatcher is not set to Background as default. So I just force kill it when the application shuts down for now. I put this in my Program.cs file in the WinForms project:
[STAThread]
static void Main()
{
 Application.ApplicationExit += Application_ApplicationExit;
 
 Application.EnableVisualStyles();
 Application.SetCompatibleTextRenderingDefault(false);
 Application.Run(new Form1());
}        
private static void Application_ApplicationExit(object sender, EventArgs e)
{
 GeoProvider.Cleanup();
}


All code provided as-is. This is copied from my own code-base, May need some additional programming to work. Use for whatever you want, how you want! If you find this helpful, please leave a comment or share a link, not required but appreciated! :)

1 comment: