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: Should I call UpdateMap even if there are not results?
90 // I could use country and city default values in that case...
91 // Problem this method: requires GeoCoordinate and I wouldn't have it here...
92 // Somehow this method should take them...
93 // TODO: if user changed the page, where is this going to appear?
95 AppResources.NoticeErrorLocationAutodetection,
96 AppResources.UnavailableAutomaticCurrentLocationMessageBox,
101 if (eventData.Result.Count > 0)
103 // TODO: Should I call UpdateMap even if there are not results?
104 // I could use country and city default values in that case...
105 // Problem this method: requires GeoCoordinate and I wouldn't have it here...
106 // Somehow this method should take them...
107 MapAddress address = eventData.Result[0].Information.Address;
108 GeoCoordinate currentGeoCoordinate = eventData.Result[0].GeoCoordinate;
110 UpdateMap(currentGeoCoordinate, address.City, address.Country);
115 private void UpdateMap(GeoCoordinate geoCoordinate, string city, string country)
117 // Create a small circle to mark the current location.
118 Ellipse myCircle = new Ellipse();
119 myCircle.Fill = new SolidColorBrush(Colors.Blue);
120 myCircle.Height = 20;
122 myCircle.Opacity = 50;
124 // Create a MapOverlay to contain the circle.
125 MapOverlay myLocationOverlay = new MapOverlay();
126 myLocationOverlay.Content = myCircle;
127 myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
128 myLocationOverlay.GeoCoordinate = geoCoordinate;
130 // Create a MapLayer to contain the MapOverlay.
131 MapLayer myLocationLayer = new MapLayer();
132 myLocationLayer.Add(myLocationOverlay);
134 this.mapWeatherInformation.Layers.Clear();
136 // TODO: problems? user could press save location and if she is fast enough she
137 // could not realize the location changed.
138 // But well... She will realize later... So.. Is this really a problem?
139 this.mapWeatherInformation.Center = geoCoordinate;
140 this.mapWeatherInformation.ZoomLevel = 13;
142 if (string.IsNullOrEmpty(city))
144 city = AppResources.DefaultCity;
146 if (string.IsNullOrEmpty(country))
148 country = AppResources.DefaultCountry;
150 this.LocationTextCityCountry.Text = String.Format(CultureInfo.InvariantCulture, "{0}, {1}", city, country);
153 // Add the MapLayer to the Map.
154 this.mapWeatherInformation.Layers.Add(myLocationLayer);
157 private static class CoordinateHelper
159 public static GeoCoordinate ConvertGeocoordinate(Geocoordinate geocoordinate)
161 return new GeoCoordinate
163 geocoordinate.Latitude,
164 geocoordinate.Longitude,
165 geocoordinate.Altitude ?? Double.NaN,
166 geocoordinate.Accuracy,
167 geocoordinate.AltitudeAccuracy ?? Double.NaN,
168 geocoordinate.Speed ?? Double.NaN,
169 geocoordinate.Heading ?? Double.NaN
174 // TODO: check data before storing :(
175 // http://stackoverflow.com/questions/4521435/what-specific-values-can-a-c-sharp-double-represent-that-a-sql-server-float-can
176 private void StoreLocation(GeoCoordinate geocoordinate)
178 Location locationItem = null;
179 using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
181 // Define the query to gather all of the to-do items.
182 // var toDoItemsInDB = from Location location in _locationDB.Locations where location.IsSelected select location;
183 locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
185 if (locationItem != null)
187 locationItem.Latitude = geocoordinate.Latitude;
188 locationItem.Longitude = geocoordinate.Longitude;
189 locationItem.Altitude = geocoordinate.Altitude;
190 locationItem.City = _city ?? "";
191 locationItem.Country = _country ?? "";
192 locationItem.HorizontalAccuracy = geocoordinate.HorizontalAccuracy;
193 locationItem.VerticalAccuracy = geocoordinate.VerticalAccuracy;
194 locationItem.Speed = geocoordinate.Speed;
195 locationItem.Course = geocoordinate.Course;
196 locationItem.IsSelected = true;
197 locationItem.LastRemoteDataUpdate = null;
201 locationItem = new Location()
203 Latitude = geocoordinate.Latitude,
204 Longitude = geocoordinate.Longitude,
205 Altitude = geocoordinate.Altitude,
207 Country = _country ?? "",
208 HorizontalAccuracy = geocoordinate.HorizontalAccuracy,
209 VerticalAccuracy = geocoordinate.VerticalAccuracy,
210 Speed = geocoordinate.Speed,
211 Course = geocoordinate.Course,
213 LastRemoteDataUpdate = null,
216 // Add a location item to the local database.
217 db.Locations.InsertOnSubmit(locationItem);
224 private GeoCoordinate ConvertLocation(Location locationItem)
226 return new GeoCoordinate
228 locationItem.Latitude,
229 locationItem.Longitude,
230 locationItem.Altitude,
231 locationItem.HorizontalAccuracy,
232 locationItem.VerticalAccuracy,
238 private void mapWeatherInformation_Tap(object sender, System.Windows.Input.GestureEventArgs e)
240 var point = e.GetPosition(this.mapWeatherInformation);
241 GeoCoordinate geocoordinate = this.mapWeatherInformation.ConvertViewportPointToGeoCoordinate(point);
242 ReverseGeocodeAndUpdateMap(geocoordinate);
245 private async void GetCurrentLocationButton_Click(object sender, RoutedEventArgs e)
249 await this.GetCurrentLocationAndUpdateMap();
253 // TODO: make sure when exception in GetCurrentLocationAndUpdateMap we catch it here.
254 // TODO: if user changed the page, where is this going to appear?
256 AppResources.NoticeErrorLocationAutodetection,
257 AppResources.UnavailableAutomaticCurrentLocationMessageBox,
258 MessageBoxButton.OK);
262 private void SaveLocationButton_Click(object sender, RoutedEventArgs e)
264 // TODO: Could there some problem if user clicks button and thread is in this very moment updating map?
265 var geoCoordinate = this.mapWeatherInformation.Center;
267 StoreLocation(geoCoordinate);
270 private void ZoomOutButton_Click(object sender, RoutedEventArgs e)
272 this.mapWeatherInformation.ZoomLevel = this.mapWeatherInformation.ZoomLevel - 1;
275 private void ZoomInButton_Click(object sender, RoutedEventArgs e)
277 this.mapWeatherInformation.ZoomLevel = this.mapWeatherInformation.ZoomLevel + 1;