2 using System.Collections.Generic;
5 using System.Windows.Navigation;
6 using Microsoft.Phone.Controls;
7 using Windows.Devices.Geolocation;
8 using System.Device.Location;
9 using System.Windows.Shapes;
10 using System.Windows.Media;
11 using Microsoft.Phone.Maps.Controls;
12 using WeatherInformation.Resources;
13 using System.Globalization;
14 using Microsoft.Phone.Maps.Services;
15 using System.Threading.Tasks;
16 using WeatherInformation.Model;
18 namespace WeatherInformation
20 public partial class MapPage : PhoneApplicationPage
22 // TODO anything better than these two instance fields? :(
24 private string _country;
28 InitializeComponent();
31 protected override void OnNavigatedTo(NavigationEventArgs e)
34 Location locationItem = null;
35 using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
37 // Define the query to gather all of the to-do items.
38 // var toDoItemsInDB = from Location location in _locationDB.Locations where location.IsSelected select location;
39 locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
42 if (locationItem != null)
44 GeoCoordinate geoCoordinate = ConvertLocation(locationItem);
46 this.UpdateMap(geoCoordinate, locationItem.City, locationItem.Country);
50 private async Task GetCurrentLocationAndUpdateMap()
52 Geolocator geolocator = new Geolocator();
53 geolocator.DesiredAccuracyInMeters = 50;
55 Geoposition geoposition = await geolocator.GetGeopositionAsync(
56 maximumAge: TimeSpan.FromSeconds(10),
57 timeout: TimeSpan.FromSeconds(10)
59 GeoCoordinate currentGeoCoordinate = CoordinateHelper.ConvertGeocoordinate(geoposition.Coordinate);
61 ReverseGeocodeAndUpdateMap(currentGeoCoordinate);
64 // TODO: problems updating Map because this method may be called when automatically retrieving
65 // the current user's location or when user taps on map tyring to choose by herself her location.
66 // There could be 2 threads updating Map at the same time. Solution: remove the feature
67 // of getting the current user's location (user must always choose her/his location instead of doing
69 private void ReverseGeocodeAndUpdateMap(GeoCoordinate currentGeoCoordinate)
71 ReverseGeocodeQuery currentReverseGeocodeQuery = new ReverseGeocodeQuery();
72 currentReverseGeocodeQuery.GeoCoordinate = currentGeoCoordinate;
73 currentReverseGeocodeQuery.QueryCompleted += QueryCompletedCallback;
74 currentReverseGeocodeQuery.QueryAsync();
77 private void QueryCompletedCallback(object sender, QueryCompletedEventArgs<IList<MapLocation>> eventData)
79 if (eventData.Cancelled)
81 // Be careful!!! If you throw exception from this point your program will finish with "Unhandled Exception".
85 Exception errorException = eventData.Error;
86 if (errorException != null)
89 AppResources.NoticeErrorLocationAutodetection,
90 AppResources.UnavailableAutomaticCurrentLocationMessageBox,
95 if (eventData.Result.Count > 0)
97 MapAddress address = eventData.Result[0].Information.Address;
98 GeoCoordinate currentGeoCoordinate = eventData.Result[0].GeoCoordinate;
100 UpdateMap(currentGeoCoordinate, address.City, address.Country);
105 private void UpdateMap(GeoCoordinate geoCoordinate, string city, string country)
107 // Create a small circle to mark the current location.
108 Ellipse myCircle = new Ellipse();
109 myCircle.Fill = new SolidColorBrush(Colors.Blue);
110 myCircle.Height = 20;
112 myCircle.Opacity = 50;
114 // Create a MapOverlay to contain the circle.
115 MapOverlay myLocationOverlay = new MapOverlay();
116 myLocationOverlay.Content = myCircle;
117 myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
118 myLocationOverlay.GeoCoordinate = geoCoordinate;
120 // Create a MapLayer to contain the MapOverlay.
121 MapLayer myLocationLayer = new MapLayer();
122 myLocationLayer.Add(myLocationOverlay);
124 this.mapWeatherInformation.Layers.Clear();
126 // TODO: problems? user could press save location and if she is fast enough she
127 // could not realize the location changed.
128 // But well... She will realize later... So.. Is this really a problem?
129 this.mapWeatherInformation.Center = geoCoordinate;
130 this.mapWeatherInformation.ZoomLevel = 13;
132 if (string.IsNullOrEmpty(city))
134 city = AppResources.DefaultCity;
136 if (string.IsNullOrEmpty(country))
138 country = AppResources.DefaultCountry;
140 this.LocationTextCityCountry.Text = String.Format(CultureInfo.InvariantCulture, "{0}, {1}", city, country);
143 // Add the MapLayer to the Map.
144 this.mapWeatherInformation.Layers.Add(myLocationLayer);
147 private static class CoordinateHelper
149 public static GeoCoordinate ConvertGeocoordinate(Geocoordinate geocoordinate)
151 return new GeoCoordinate
153 geocoordinate.Latitude,
154 geocoordinate.Longitude,
155 geocoordinate.Altitude ?? Double.NaN,
156 geocoordinate.Accuracy,
157 geocoordinate.AltitudeAccuracy ?? Double.NaN,
158 geocoordinate.Speed ?? Double.NaN,
159 geocoordinate.Heading ?? Double.NaN
164 // TODO: check data before storing :(
165 // http://stackoverflow.com/questions/4521435/what-specific-values-can-a-c-sharp-double-represent-that-a-sql-server-float-can
166 private void StoreLocation(GeoCoordinate geocoordinate)
168 Location locationItem = null;
169 using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
171 // Define the query to gather all of the to-do items.
172 // var toDoItemsInDB = from Location location in _locationDB.Locations where location.IsSelected select location;
173 locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
175 if (locationItem != null)
177 locationItem.Latitude = geocoordinate.Latitude;
178 locationItem.Longitude = geocoordinate.Longitude;
179 locationItem.Altitude = geocoordinate.Altitude;
180 locationItem.City = _city ?? "";
181 locationItem.Country = _country ?? "";
182 locationItem.HorizontalAccuracy = geocoordinate.HorizontalAccuracy;
183 locationItem.VerticalAccuracy = geocoordinate.VerticalAccuracy;
184 locationItem.Speed = geocoordinate.Speed;
185 locationItem.Course = geocoordinate.Course;
186 locationItem.IsSelected = true;
187 locationItem.LastRemoteDataUpdate = null;
191 locationItem = new Location()
193 Latitude = geocoordinate.Latitude,
194 Longitude = geocoordinate.Longitude,
195 Altitude = geocoordinate.Altitude,
197 Country = _country ?? "",
198 HorizontalAccuracy = geocoordinate.HorizontalAccuracy,
199 VerticalAccuracy = geocoordinate.VerticalAccuracy,
200 Speed = geocoordinate.Speed,
201 Course = geocoordinate.Course,
203 LastRemoteDataUpdate = null,
206 // Add a location item to the local database.
207 db.Locations.InsertOnSubmit(locationItem);
214 private GeoCoordinate ConvertLocation(Location locationItem)
216 return new GeoCoordinate
218 locationItem.Latitude,
219 locationItem.Longitude,
220 locationItem.Altitude,
221 locationItem.HorizontalAccuracy,
222 locationItem.VerticalAccuracy,
228 private void mapWeatherInformation_Tap(object sender, System.Windows.Input.GestureEventArgs e)
230 var point = e.GetPosition(this.mapWeatherInformation);
231 GeoCoordinate geocoordinate = this.mapWeatherInformation.ConvertViewportPointToGeoCoordinate(point);
232 ReverseGeocodeAndUpdateMap(geocoordinate);
235 private async void GetCurrentLocationButton_Click(object sender, RoutedEventArgs e)
239 await this.GetCurrentLocationAndUpdateMap();
243 // TODO: make sure when exception in GetCurrentLocationAndUpdateMap we catch it here.
245 AppResources.NoticeErrorLocationAutodetection,
246 AppResources.UnavailableAutomaticCurrentLocationMessageBox,
247 MessageBoxButton.OK);
251 private void SaveLocationButton_Click(object sender, RoutedEventArgs e)
253 // TODO: Could there some problem if user clicks button and thread is in this very moment updating map?
254 var geoCoordinate = this.mapWeatherInformation.Center;
256 StoreLocation(geoCoordinate);
259 private void ZoomOutButton_Click(object sender, RoutedEventArgs e)
261 this.mapWeatherInformation.ZoomLevel = this.mapWeatherInformation.ZoomLevel - 1;
264 private void ZoomInButton_Click(object sender, RoutedEventArgs e)
266 this.mapWeatherInformation.ZoomLevel = this.mapWeatherInformation.ZoomLevel + 1;