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)
33 // TODO: I am not saving the UI state. If location changed but it was not saved
34 // user will have to pick her location again :(
35 Location locationItem = null;
36 using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
38 // Define the query to gather all of the to-do items.
39 // var toDoItemsInDB = from Location location in _locationDB.Locations where location.IsSelected select location;
40 locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
43 if (locationItem != null)
45 GeoCoordinate geoCoordinate = ConvertLocation(locationItem);
47 this.UpdateMap(geoCoordinate, locationItem.City, locationItem.Country);
51 private async Task GetCurrentLocationAndUpdateMap()
53 Geolocator geolocator = new Geolocator();
54 geolocator.DesiredAccuracyInMeters = 50;
56 Geoposition geoposition = await geolocator.GetGeopositionAsync(
57 maximumAge: TimeSpan.FromSeconds(10),
58 timeout: TimeSpan.FromSeconds(10)
60 GeoCoordinate currentGeoCoordinate = CoordinateHelper.ConvertGeocoordinate(geoposition.Coordinate);
62 ReverseGeocodeAndUpdateMap(currentGeoCoordinate);
65 // TODO: problems updating Map because this method may be called when automatically retrieving
66 // the current user's location or when user taps on map tyring to choose by herself her location.
67 // There could be 2 threads updating Map at the same time. Solution: remove the feature
68 // of getting the current user's location (user must always choose her/his location instead of doing
70 private void ReverseGeocodeAndUpdateMap(GeoCoordinate currentGeoCoordinate)
72 ReverseGeocodeQuery currentReverseGeocodeQuery = new ReverseGeocodeQuery();
73 currentReverseGeocodeQuery.GeoCoordinate = currentGeoCoordinate;
74 currentReverseGeocodeQuery.QueryCompleted += QueryCompletedCallback;
75 currentReverseGeocodeQuery.QueryAsync();
78 private void QueryCompletedCallback(object sender, QueryCompletedEventArgs<IList<MapLocation>> eventData)
80 if (eventData.Cancelled)
82 // Be careful!!! If you throw exception from this point your program will finish with "Unhandled Exception".
86 Exception errorException = eventData.Error;
87 if (errorException != null)
89 // TODO: if user changed the page, where is this going to appear?
91 AppResources.NoticeErrorLocationAutodetection,
92 AppResources.UnavailableAutomaticCurrentLocationMessageBox,
97 if (eventData.Result.Count > 0)
99 // TODO: Should I call UpdateMap even if there are not results?
100 // I could use country and city default values in that case...
101 // Problem this method: requires GeoCoordinate and I wouldn't have it here...
102 // Somehow this method should take them...
103 MapAddress address = eventData.Result[0].Information.Address;
104 GeoCoordinate currentGeoCoordinate = eventData.Result[0].GeoCoordinate;
106 UpdateMap(currentGeoCoordinate, address.City, address.Country);
111 private void UpdateMap(GeoCoordinate geoCoordinate, string city, string country)
113 // Create a small circle to mark the current location.
114 Ellipse myCircle = new Ellipse();
115 myCircle.Fill = new SolidColorBrush(Colors.Blue);
116 myCircle.Height = 20;
118 myCircle.Opacity = 50;
120 // Create a MapOverlay to contain the circle.
121 MapOverlay myLocationOverlay = new MapOverlay();
122 myLocationOverlay.Content = myCircle;
123 myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
124 myLocationOverlay.GeoCoordinate = geoCoordinate;
126 // Create a MapLayer to contain the MapOverlay.
127 MapLayer myLocationLayer = new MapLayer();
128 myLocationLayer.Add(myLocationOverlay);
130 this.mapWeatherInformation.Layers.Clear();
132 // TODO: problems? user could press save location and if she is fast enough she
133 // could not realize the location changed.
134 // But well... She will realize later... So.. Is this really a problem?
135 this.mapWeatherInformation.Center = geoCoordinate;
136 this.mapWeatherInformation.ZoomLevel = 13;
138 if (string.IsNullOrEmpty(city))
140 city = AppResources.DefaultCity;
142 if (string.IsNullOrEmpty(country))
144 country = AppResources.DefaultCountry;
146 this.LocationTextCityCountry.Text = String.Format(CultureInfo.InvariantCulture, "{0}, {1}", city, country);
149 // Add the MapLayer to the Map.
150 this.mapWeatherInformation.Layers.Add(myLocationLayer);
153 private static class CoordinateHelper
155 public static GeoCoordinate ConvertGeocoordinate(Geocoordinate geocoordinate)
157 return new GeoCoordinate
159 geocoordinate.Latitude,
160 geocoordinate.Longitude,
161 geocoordinate.Altitude ?? Double.NaN,
162 geocoordinate.Accuracy,
163 geocoordinate.AltitudeAccuracy ?? Double.NaN,
164 geocoordinate.Speed ?? Double.NaN,
165 geocoordinate.Heading ?? Double.NaN
170 // TODO: check data before storing :(
171 // http://stackoverflow.com/questions/4521435/what-specific-values-can-a-c-sharp-double-represent-that-a-sql-server-float-can
172 private void StoreLocation(GeoCoordinate geocoordinate)
174 Location locationItem = null;
175 using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
177 // Define the query to gather all of the to-do items.
178 // var toDoItemsInDB = from Location location in _locationDB.Locations where location.IsSelected select location;
179 locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
181 if (locationItem != null)
183 locationItem.Latitude = geocoordinate.Latitude;
184 locationItem.Longitude = geocoordinate.Longitude;
185 locationItem.Altitude = geocoordinate.Altitude;
186 locationItem.City = _city ?? "";
187 locationItem.Country = _country ?? "";
188 locationItem.HorizontalAccuracy = geocoordinate.HorizontalAccuracy;
189 locationItem.VerticalAccuracy = geocoordinate.VerticalAccuracy;
190 locationItem.Speed = geocoordinate.Speed;
191 locationItem.Course = geocoordinate.Course;
192 locationItem.IsSelected = true;
193 locationItem.LastRemoteDataUpdate = null;
197 locationItem = new Location()
199 Latitude = geocoordinate.Latitude,
200 Longitude = geocoordinate.Longitude,
201 Altitude = geocoordinate.Altitude,
203 Country = _country ?? "",
204 HorizontalAccuracy = geocoordinate.HorizontalAccuracy,
205 VerticalAccuracy = geocoordinate.VerticalAccuracy,
206 Speed = geocoordinate.Speed,
207 Course = geocoordinate.Course,
209 LastRemoteDataUpdate = null,
212 // Add a location item to the local database.
213 db.Locations.InsertOnSubmit(locationItem);
220 private GeoCoordinate ConvertLocation(Location locationItem)
222 return new GeoCoordinate
224 locationItem.Latitude,
225 locationItem.Longitude,
226 locationItem.Altitude,
227 locationItem.HorizontalAccuracy,
228 locationItem.VerticalAccuracy,
234 private void mapWeatherInformation_Tap(object sender, System.Windows.Input.GestureEventArgs e)
236 var point = e.GetPosition(this.mapWeatherInformation);
237 GeoCoordinate geocoordinate = this.mapWeatherInformation.ConvertViewportPointToGeoCoordinate(point);
238 ReverseGeocodeAndUpdateMap(geocoordinate);
241 private async void GetCurrentLocationButton_Click(object sender, RoutedEventArgs e)
245 await this.GetCurrentLocationAndUpdateMap();
249 // TODO: make sure when exception in GetCurrentLocationAndUpdateMap we catch it here.
250 // TODO: if user changed the page, where is this going to appear?
252 AppResources.NoticeErrorLocationAutodetection,
253 AppResources.UnavailableAutomaticCurrentLocationMessageBox,
254 MessageBoxButton.OK);
258 private void SaveLocationButton_Click(object sender, RoutedEventArgs e)
260 // TODO: Could there some problem if user clicks button and thread is in this very moment updating map?
261 var geoCoordinate = this.mapWeatherInformation.Center;
263 StoreLocation(geoCoordinate);
266 private void ZoomOutButton_Click(object sender, RoutedEventArgs e)
268 this.mapWeatherInformation.ZoomLevel = this.mapWeatherInformation.ZoomLevel - 1;
271 private void ZoomInButton_Click(object sender, RoutedEventArgs e)
273 this.mapWeatherInformation.ZoomLevel = this.mapWeatherInformation.ZoomLevel + 1;