/// <summary> /// Standard click event to get advice based on a move request /// </summary> private void HResultGet_Click(object sender, RoutedEventArgs e) { Task.Run(() => { //Check if old and new house are found if ((p1.Item1 == 0 && p1.Item2 == 0) || (p2.Item1 == 0 && p2.Item2 == 0)) { Dispatcher.Invoke(new Action(() => { //Reset everything routeGeometry = new LineString(); MemoryLayer memoryLayer = (MemoryLayer)MyMapControl.Map.Layers.FindLayer("Route Layer").ElementAt(0); memoryLayer.DataSource = CreateMemoryProvider(); memoryLayer.ClearCache(); memoryLayer.ViewChanged(true, memoryLayer.Envelope, 1); MyMapControl.Map.ViewChanged(true); hResult.Text = "Get address coordinates first!"; }), DispatcherPriority.ContextIdle); } else { Dispatcher.Invoke(new Action(() => { //Disable the button to avoid parallel calls hResultGet.IsEnabled = false; }), DispatcherPriority.ContextIdle); try { //Get route from old to new house var route = GetRoute(p1, p2).Result; if (route != null && route.Count > 1) { //Get distance and duration of moving from one house to another var meta = route[route.Count - 1]; route.RemoveAt(route.Count - 1); //Compose moving duration string string duration = "Expected moving duration - " + Math.Floor(meta.Y / 60.0 / 60.0) .ToString(CultureInfo.InvariantCulture) + " hours, " + Math.Floor(meta.Y / 60.0 - Math.Floor(meta.Y / 60.0 / 60.0) * 60.0) .ToString(CultureInfo.InvariantCulture) + " minutes, " + Math.Floor(meta.Y - Math.Floor(meta.Y / 60.0 / 60.0) * 60.0 * 60.0 - Math.Floor(meta.Y / 60.0) * 60.0) .ToString(CultureInfo.InvariantCulture) + " seconds. "; //Get weather forecast for next 5 days at old house var weather = GetForecast(p1).Result; //Get individual forecast list //Take only forecasts during working hours (8 to 22) //Order by weather condition ids: https://openweathermap.org/weather-conditions, (generally higher ids are better) //Then order by temperature, (generally higher temperature is better) //Get element 0, which is the best var bestT = weather.list .Where(a => { var atime = FromSecondsSinceUnixEpoch(a.dt); return(atime.Hour > 8 && atime.Hour < 22); }) .OrderByDescending(a => a.weather[0].id) .ThenByDescending(a => a.main.temp) .ElementAt(0); //Compose forecast string string forecast = "Best time to move within 5 days - " + FromSecondsSinceUnixEpoch(bestT.dt).ToString("dddd, dd MMMM yyyy HH:mm", CultureInfo.InvariantCulture) + " because then weather will be " + bestT.weather[0].main.ToLowerInvariant() + ", " + bestT.weather[0].description.ToLowerInvariant() + " to be exact; " + "expected temparature - " + Math.Floor(bestT.main.temp).ToString(CultureInfo.InvariantCulture) + " degrees Celsius. "; Dispatcher.Invoke(new Action(() => { //Use LINQ to convert geographical points to screen ones routeGeometry = new LineString(route.Select( a => SphericalMercator.FromLonLat(a.X, a.Y))); //Find the specific map layer with routing data MemoryLayer memoryLayer = (MemoryLayer)MyMapControl.Map.Layers.FindLayer("Route Layer").ElementAt(0); //Create a new memory provider with our new route memoryLayer.DataSource = CreateMemoryProvider(); //Clear render cache memoryLayer.ClearCache(); //Inform layer of a data change, making it re-render the whole thing memoryLayer.ViewChanged(true, memoryLayer.Envelope, 1); //Inform map of a data change, making it re-render the whole thing MyMapControl.Map.ViewChanged(true); //Update advice text hResult.Text = duration + forecast; }), DispatcherPriority.ContextIdle); } else { Dispatcher.Invoke(new Action(() => { //Same as higher but with an empty route routeGeometry = new LineString(); MemoryLayer memoryLayer = (MemoryLayer)MyMapControl.Map.Layers.FindLayer("Route Layer").ElementAt(0); memoryLayer.DataSource = CreateMemoryProvider(); memoryLayer.ClearCache(); memoryLayer.ViewChanged(true, memoryLayer.Envelope, 1); MyMapControl.Map.ViewChanged(true); hResult.Text = "Failed to find a path!"; }), DispatcherPriority.ContextIdle); } } catch (Exception) { Dispatcher.Invoke(new Action(() => { //Same as higher but with an empty route routeGeometry = new LineString(); MemoryLayer memoryLayer = (MemoryLayer)MyMapControl.Map.Layers.FindLayer("Route Layer").ElementAt(0); memoryLayer.DataSource = CreateMemoryProvider(); memoryLayer.ClearCache(); memoryLayer.ViewChanged(true, memoryLayer.Envelope, 1); MyMapControl.Map.ViewChanged(true); hResult.Text = "An error occured during advice gathering!"; }), DispatcherPriority.ContextIdle); } Dispatcher.Invoke(new Action(() => { //Enable the Get Advice button for future use hResultGet.IsEnabled = true; }), DispatcherPriority.ContextIdle); } }); }