/// <summary> /// Refreshes the list of items obtained from the API and populates the view model /// </summary> public async Task Refresh() { // get bounding box of current map var topLeft = TheMap.ConvertViewportPointToGeoCoordinate(new Point(0, 0)); var bottomRight = TheMap.ConvertViewportPointToGeoCoordinate(new Point(TheMap.ActualWidth, TheMap.ActualHeight)); var box = new BoundingBox(topLeft.Latitude, bottomRight.Latitude, topLeft.Longitude, bottomRight.Longitude); // // TODO: invoke API that returns a list of point-of-interest items now in view on the map. This will populate // an observable collection of IMappable items on the ApiViewModel class (with the name Results). As that // collection is populated, the Results_CollectionChanged callback will fire to create the appropriate // point-of-interest pins and associate them with the map. // this.DefaultViewModel.ApiStatus = await _tomTomApi.GetCameras(box, (Int32)App.Current.Resources["MaxResults"]); // if there's a problem in the request, show a message box if (!DefaultViewModel.ApiStatus.IsSuccessStatusCode) { MessageBox.Show( String.Format("There was an error in handling the last request.\n\nCode: {0}\n\nMessage: {1}", (Int32) DefaultViewModel.ApiStatus.StatusCode, String.IsNullOrEmpty(DefaultViewModel.ApiStatus.Message) ? DefaultViewModel.ApiStatus.StatusCode.ToString() : DefaultViewModel.ApiStatus.Message), "Request Error", MessageBoxButton.OK); } }
/// <summary> /// Refreshes the list of items obtained from the API and populates the view model /// </summary> /// <param name="box">Bounding box of current map view</param> /// <param name="id">Id of IMappable item that should be selected</param> public async Task Refresh(BoundingBox box, String id = null) { // // TODO: refresh the items in the panel to reflect points of interest in the current map view. You // will invoke your target API that populates the view model's ObservableCollection and returns // a status object. The "NoResults" entry in the view model is used to drive the visibility // of text that appears when the query returns no elements (versus providing no feedback). // // this.DefaultViewModel["ApiStatus"] = await _tomTomApi.GetCameras(box, this.MaxResults); this.DefaultViewModel["NoResults"] = _tomTomApi.TomTomViewModel.Results.Count == 0; // if there's an IMappable ID provided, select that item automatically if (id != null) MappableListView.SelectedItem = MappableListView.Items.Where((c) => (c as IMappable).Id == id).FirstOrDefault(); // signal that panel has been refreshed OnRefreshed(); }
public MainPage() { this.InitializeComponent(); // view model this.DefaultViewModel["PendingRefresh"] = false; // check to see if this is the first time application is being executed by checking for data in local settings. // After checking add some notional data as marker for next time app is run. This will be used to determine whether // to prompt the user (or not) that location services are not turned on for the app/system. Without this check, the // first time the app is run, it will provide a system prompt, and if that prompt is dismissed without granting // access the propmpt displayed by the application would also appear unnecessarily. _firstRun = ApplicationData.Current.LocalSettings.Values.Count == 0; if (_firstRun) ApplicationData.Current.LocalSettings.Values.Add( new System.Collections.Generic.KeyValuePair<string, object>("InitialRunDate", DateTime.UtcNow.ToString())); this.SizeChanged += (s, e) => { // determine if there's been a change in orientation that doesn't require notice that the map view has changed (e.g., app open, snapped mode transitions) if (_priorOrientation == ApplicationView.Value) return; _noRefreshRequiredViewChange = (_priorOrientation == ApplicationViewState.Snapped || ApplicationView.Value == ApplicationViewState.Snapped); _priorOrientation = ApplicationView.Value; VisualStateManager.GoToState(LeftPanel, ApplicationView.Value.ToString(), true); }; // whenever map view changes track center point and zoom level in page state TheMap.ViewChangeEnded += (s, e) => { // save new center/zoom for page state _pageState.MapCenter = new LatLong(TheMap.TargetCenter.Latitude, TheMap.TargetCenter.Longitude); _pageState.Zoom = TheMap.TargetZoomLevel; // ViewChangeEnded fires a bit too often, so retain bounding box to determine if the view truly has changed BoundingBox thisBox = new BoundingBox(TheMap.TargetBounds.North, TheMap.TargetBounds.South, TheMap.TargetBounds.West, TheMap.TargetBounds.East); // determine if view change should notify user of pending refresh requirement if (_retainRefreshRequiredViewChange) this.DefaultViewModel["PendingRefresh"] = _pageState.PendingRefresh; else if (_noRefreshRequiredViewChange) this.DefaultViewModel["PendingRefresh"] = false; else if (App.InitialMapResizeHasOccurred) this.DefaultViewModel["PendingRefresh"] = (thisBox != _lastBox); // update state variables _lastBox = thisBox; if (App.InitialMapResizeHasOccurred) _noRefreshRequiredViewChange = false; _retainRefreshRequiredViewChange = false; App.InitialMapResizeHasOccurred = true; }; // if refresh prompt is tapped, refresh the map RefreshPrompt.Tapped += async (s, e) => { await LeftPanel.Refresh(_lastBox); this.DefaultViewModel["PendingRefresh"] = false; }; // a tap on map will cause refresh is one is predicated TheMap.Tapped += async (s, e) => { if ((Boolean)this.DefaultViewModel["PendingRefresh"]) { await LeftPanel.Refresh(_lastBox); this.DefaultViewModel["PendingRefresh"] = false; } }; // set the reference to the current map for the LeftPanel (note: using Element binding will not handle all of the page navigation scenarios) LeftPanel.Map = TheMap; // whenever the contents of left panel are refreshed, save the map coordinates that were in play as part of the page state LeftPanel.Refreshed += (s, e) => { _pageState.MapBox = new BoundingBox(TheMap.TargetBounds.North, TheMap.TargetBounds.South, TheMap.TargetBounds.West, TheMap.TargetBounds.East); }; // whenver a new item is selected in the left panel, update the map pins and save the item selected as part of the page state LeftPanel.ItemSelected += (s, e) => { TheMap.HighlightPointOfInterestPin(e.NewItem, true); TheMap.HighlightPointOfInterestPin(e.OldItem, false); this._pageState.SelectedItemId = e.NewItem == null ? null : e.NewItem.Id; }; // whenever a new location is selected from the SearchFlyout (this is NOT the Search charm) update the position accordingly SearchFlyout.LocationChanged += (s, e) => { GotoLocation(e.Position); SearchFlyout.Hide(); }; // manage SearchFlyout visibility/interaction this.Tapped += (s, e) => { if (SearchFlyout.IsOpen) { SearchFlyout.Hide(); e.Handled = true; } }; BottomAppBar.Opened += (s, e) => { SearchFlyout.Hide(); }; SearchFlyout.Tapped += (s, e) => { e.Handled = true; }; // allow type-to-search for Search charm SearchPane.GetForCurrentView().ShowOnKeyboardInput = true; // The BingMaps API allows use of a "session key" if the application leverages the Bing Maps control. By using the session // key instead of the API key, only one transaction is logged agains the key versus one transaction for every API call! This // code sets the key asynchronously and stored it as a resource so it's available when the REST API's are invoked. TheMap.Loaded += async (s, e) => { if (!Application.Current.Resources.ContainsKey("BingMapsSessionKey")) Application.Current.Resources.Add("BingMapsSessionKey", await TheMap.GetSessionIdAsync()); }; }