In the previous section, we created our data service base interface class for our data service, and we defined several different instance methods that our class will be utilizing. This will essentially be used by each of our ViewModels
along with the Views (pages). Let's now start to implement the code required for our WalkDataService
class, by performing the following steps:
Services
folder, by choosing Add | New File..., as you did when creating the DataService
interface in the previous section entitled Creating the DataService API for the TrackMyWalks app located within this chapter.WalkDataService
for the name of the new class that you want to create, and click on the New button to allow the wizard to proceed and create the new file.WalkDataService.cs
file is displayed within the code editor, and enter the following code snippet:// // WalkDataService.cs // TrackMyWalks API Data Service Class // // Created by Steven F. Daniel on 30/10/2016. // Copyright © 2016 GENIESOFT STUDIOS. All rights reserved. // using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Net.Http; using TrackMyWalks.Models; using Newtonsoft.Json; namespace TrackMyWalks.Services {
WalkDataService
class constructor, so that it can inherit from both our WalkWebService
base-class as well as the IWalkDataService
class:public class WalkDataService : WalkWebService, IWalkDataService {
_baseUri
and _headers
. The _baseUri
property will be used to store the base URL
and the _headers
property of the IDictionary<string, string>
type that will be used to store the header information that we want to pass to our WalkWebService
class.zumo-api-version
is basically a special header value that is used by the HTTP client when communicating with Microsoft Azure databases. Proceed and enter in the following code snippet.readonly Uri _baseUri; readonly IDictionary<string, string> _headers; // Our Class Constructor that accepts the Azure Database // Uri path public WalkDataService(Uri baseUri) { _baseUri = baseUri; _headers = new Dictionary<string, string>(); _headers.Add("zumo-api-version", "2.0.0"); }
GetWalkEntriesAsync
instance method that will retrieve all WalkEntries
that are contained within our database. We'll define a url
variable that constructs a new Uri
object using our _baseUri
URL and combining this with our walkEntries
database table within the tables
section of our TrackMyWalks
Azure database and call the SendRequestAsync
WalkWebService
base-class instance method.HttpMethod.Get
method type to tell our base class that we are ready to retrieve our WalkEntries
. Proceed and enter in the following code snippet:// API to retrieve our Walk Entries from our database public async Task<IList<WalkEntries>> GetWalkEntriesAsync() { var url = new Uri(_baseUri, "/tables/walkentries"); return await SendRequestAsync<WalkEntries[]> (url, HttpMethod.Get, _headers); }
AddWalkEntryAsync
instance method that will add walk entry information to the walkEntries
table contained within our database. We define a url
variable that constructs a new Uri
object using our _baseUri
URL and combining this with the walkEntries
database table within the tables
section of our TrackMyWalks
Azure database and call the SendRequestAsyncWalkWebService
base-class instance method.HttpMethod.Post
method type that will tell our base class that we are ready to submit information to our walkEntries
database table. Proceed and enter in the following code snippet:// API to add our Walk Entry information to the database public async Task<WalkEntries> AddWalkEntryAsync( WalkEntries entry) { var url = new Uri(_baseUri, "/tables/walkentries"); await SendRequestAsync<WalkEntries>(url,HttpMethod.Post, _headers, entry); }
DeleteWalkEntryAsync
instance method that will permanently delete associated walk entry information from our walkEntries
table contained within our database. We'll define a url
variable that constructs a new Uri
object using our _baseUri
URL and combining this with our walkEntries
database table, and pass in the Id
value of our selected walk entry within the WalksPageListView
.SendRequestAsyncWalkWebService
base class instance method. We'll pass in the HttpMethod.Delete
method type that will tell our base class that we are ready to permanently delete the walk entry within our walkEntries
database table. Proceed and enter in the following code snippet:// API to delete our Walk Entry from the database public async Task DeleteWalkEntryAsync(WalkEntries entry) { var url = new Uri(_baseUri, string.Format("/tables/walken tries/{0}", entry.Id)); await SendRequestAsync<WalkEntries>(url,HttpMethod.Delete , _headers); } } }
In the preceding code snippet, we began by implementing each of the instance methods that we defined within our IWalkDataService
interface class. We used the SendRequestAsync
method on our base class, and passed in the API details, along with the HttpMethod
type, and the zumo-api-version
header information. You will have noticed that we passed in the WalkEntries
data model object. This is so that the object can be serialized and added to the HTTP request message content.
If you are interested in learning more HTTP, please refer to the Hypertext Transfer Protocol guide located at https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol .
The HTTP class exposes several different types of HTTP methods that are used by the HttpMethod
class, which are explained in the following table.
HTTP methods |
Description |
|
This type tells the |
|
This type tells the |
|
This type tells the |
If you are interested in learning more about client and server versioning in Mobile Apps and Mobile Services, please refer to the Microsoft Azure documentation located at https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-client-and-server-versioning/.
In the next section, we will update our WalkBaseViewModel
so that it can use our DataService
API class, and initialize our Microsoft Azure TrackMyWalks
database.
In the previous sections, we created the interfaces classes that will be used by our WalkWebService
and WalkDataService
class to enable our TrackMyWalks
application to communicate with the database that is stored within the Microsoft Azure platform.
Our next step is to begin implementing the code that will be required to make a connection to our TrackMyWalks
Microsoft Azure database so that our app uses live data instead of the local, hard-coded data that we currently have in place.
Let's look at how we can achieve this, by following the steps:
WalkBaseViewModel.cs
file is displayed within the code editor, and enter in the following highlighted code sections as shown in the code snippet: //
// WalkBaseViewModel.cs
// TrackMyWalks Base ViewModel
//
// Created by Steven F. Daniel on 22/08/2016.
// Copyright © 2016 GENIESOFT STUDIOS. All rights reserved.
//
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using TrackMyWalks.Services;
namespace TrackMyWalks.ViewModels
{
public abstract class WalkBaseViewModel :
INotifyPropertyChanged
{
protected IWalkNavService NavService {
get; private set; }
bool _isProcessBusy;
public bool IsProcessBusy
{
get { return _isProcessBusy; }
set
{
_isProcessBusy = value;
OnPropertyChanged();
OnIsBusyChanged();
}
}
IWalkDataService
interface property called _azureDatabaseService
. Tis will store and retrieve the value of our TrackMyWalks
Azure database URL. The AzureDatabaseService
property contains both the getter (get
) and setter (set
) implementations that. When we set the AzureDatabaseService
property, we assign this value to our _azureDatabaseService
variable, and then call the OnPropertyChanged
instance methods to tell the ViewModels
that a change has been made:IWalkDataService _azureDatabaseService; public IWalkDataService AzureDatabaseService { get { return _azureDatabaseService; } set { _azureDatabaseService = value; OnPropertyChanged(); } }
WalkBaseViewModel
class constructor and create an instance to our WalkDataService
class, that inherits from the IWalkDataService
interface class, and then assign this to our AzureDatabaseService
property so that it can be used throughout each of our ViewModels
:protected WalkBaseViewModel(IWalkNavService navService) { // Declare our Navigation Service and Azure Database URL var WALKS_URL = "https://trackmywalks.azurewebsites.net"; NavService = navService; AzureDatabaseService = new WalkDataService(new Uri(WALKS_URL, UriKind.RelativeOrAbsolute)); } public abstract Task Init(); public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs( propertyName)); } } protected virtual void OnIsBusyChanged() { // We are processing our Walks Trail Information } } public abstract class WalkBaseViewModel<WalkParam> : WalkBaseViewModel { protected WalkBaseViewModel(IWalkNavService navService) : base(navService) { } public override async Task Init() { await Init(default(WalkParam)); } public abstract Task Init(WalkParam walkDetails); } }
In the preceding code snippet, we begin by creating a AzureDatabaseService
property that inherits from our IWalkDataService
class, and then created its associated getter and setter qualifiers. Next, we updated the WalkBaseViewModel
class constructor to set the AzureDatabaseService
property to an instance of WalkDataService
class so that it can be used throughout each of our ViewModels
.
Now that we have modified our WalkBaseViewModel
class so that it will be used by any ViewModel that inherits from this base class, our next step is to begin modifying the WalkEntryViewModel
that will utilize our WalkDataService
class, so that any new walk information that is entered will be saved back to our Azure database. Once that's done we can begin storing walk entry information when the Save button is pressed.
Let's look at how we can achieve this with the following steps:
WalkEntryViewModel.cs
file is displayed within the code editor, and enter in the following highlighted code sections as shown in the code snippet:// // WalkEntryViewModel.cs // TrackMyWalks ViewModels // // Created by Steven F. Daniel on 22/08/2016. // Copyright © 2016 GENIESOFT STUDIOS. All rights reserved. // using System.Threading.Tasks; using TrackMyWalks.Models; using TrackMyWalks.Services; using TrackMyWalks.ViewModels; using Xamarin.Forms; using System; namespace TrackMyWalks { public class WalkEntryViewModel : WalkBaseViewModel { IWalkLocationService myLocation; string _title; public string Title { get { return _title; } set { _title = value; OnPropertyChanged(); SaveCommand.ChangeCanExecute(); } } ... ...
ExecuteSaveCommand
instance method to include a check to see if our ImageUrl
field contains a value, otherwise store an empty placeholder image for the ImageUrl
property when the SaveToolBarItem
has been pressed. Proceed and enter in the following highlighted code sections:async Task ExecuteSaveCommand() { // Check to see if we are in the middle of processing // a request. if (IsProcessBusy) return; // Initialise our Walk Entry Model to state that we are // in the middle of updating details to the database. IsProcessBusy = true; // Set up our New Walk item model var newWalkItem = new WalkEntries { Title = this.Title, Notes = this.Notes, Latitude = this.Latitude, Longitude = this.Longitude, Kilometers = this.Kilometers, Difficulty = this.Difficulty, Distance = this.Distance, ImageUrl = (this.ImageUrl == null ? new Uri("https://heuft.com/upload/image/4 00x267/no_image_placeholder.png") : new Uri(this.ImageUrl)) }; // Upon exiting our New Walk Entry Page, we need to // stop checking for location updates myLocation = null;
AddWalkEntryAsync
instance method, contained within the AzureDatabaseService
class to store the newly entered information. We'll include a reference to our NavService.PreviousPage
method, which is declared within the IWalkNavService
interface class to allow our WalkEntryPage
to navigate back to the previous calling page, before finally initializing our IsProcessBusy
indicator to false
to inform our ViewModel that we are no longer processing. Proceed and enter in the following highlighted code sections:try { // Save the details entered to our Azure Database await AzureDatabaseService.AddWalkEntryAsync(newWalkItem); await NavService.PreviousPage(); } finally { // Re-Initialise our Process Busy Indicator IsProcessBusy = false; } } // method to check for any form errors bool ValidateFormDetails() { return !string.IsNullOrWhiteSpace(Title); } public override async Task Init() { await Task.Factory.StartNew(() => { Title = "New Walk"; Difficulty = "Easy"; Distance = 1.0; }); } } }
In the preceding code snippet, we modified the ExecuteSaveCommand
instance method to include a check to see if our ImageUrl
field contains a value prior to storing the information within the ImageUrl
property. If we have determined that this property is empty, we proceed to assign an empty placeholder image for the ImageUrl
property to avoid our application performing unexpected results.
In the next step, we attempt to make a call to our AddWalkEntryAsync
instance method, contained within our AzureDatabaseService
class to store the newly entered information.
Next, we'll include a reference to our NavService.PreviousPage
method, which is declared within the IWalkNavService
interface class to allow our WalkEntryPage
to navigate back to the previous calling page when the Save button has been pressed. Finally, we'll initialize our IsProcessBusy
indicator to false
to inform our ViewModel that we are no longer processing.
In this section, we will proceed to update our WalksPageViewModel
ViewModel to reference our WalkDataService
class. Since our WalksPageViewModel
is used to display information from our WalkEntries
model, we will need to update this so that it retrieves this information from the TrackMyWalks
database, located within our Microsoft Azure platform, and display this within the ListView
control.
Let's look at how we can achieve this with the following steps:
WalksPageViewModel.cs
file is displayed within the code editor, and enter in the following highlighted code sections as shown in the following code snippet:// // WalksPageViewModel.cs // TrackMyWalks ViewModels // // Created by Steven F. Daniel on 22/08/2016. // Copyright © 2016 GENIESOFT STUDIOS. All rights reserved. // using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using TrackMyWalks.Models; using TrackMyWalks.Services; using Xamarin.Forms; namespace TrackMyWalks.ViewModels { public class WalksPageViewModel : WalkBaseViewModel { ObservableCollection<WalkEntries> _walkEntries; public ObservableCollection<WalkEntries> walkEntries { get { return _walkEntries; } set { _walkEntries = value; OnPropertyChanged(); } } ... ...
LoadWalkDetails
instance method to check to see if we are already in the middle of processing walk trail items within the ListView
. Next we'll proceed to populate our WalkEntries
array with items retrieved from our GetWalkEntriesAsync
Azure web service instance method call to populate our WalkEntries
asynchronously and use the await
keyword to wait until the Task
completed. Finally, we'll initialize our IsProcessBusy
indicator to false
to inform our ViewModel that we are no longer processing. Proceed and enter in the following highlighted code sections:public async Task LoadWalkDetails() { // Check to see if we are already processing our // Walk Trail Items if (IsProcessBusy) { return; } // If we aren't currently processing, we need to // initialise our variable to true IsProcessBusy = true; try { // Populate our Walk Entries array with items // from our Azure Web Service walkEntries = new ObservableCollection<WalkEntries> (await AzureDatabaseService.GetWalkEntriesAsync()); } finally { // Re-initialise our process busy value back to false IsProcessBusy = false; } } ... ...
DeleteWalkItem
command property within our class, that will be used within our WalksPage
to handle whenever we click on a walk item within our ListView
. The DeleteWalkItem
property will then run an action, whenever the Delete
option has been chosen from the ActionSheet
, to delete the chosen item as determined by our trailDetails
to permanently remove the record from our TrackMyWalks
database located within our Microsoft Azure platform. Proceed and enter in the following highlighted code sections:Command _deleteWalkItem; public Command DeleteWalkItem { get { return _deleteWalkItem ?? (_deleteWalkItem = new Command(async (trailDetails) => await AzureDatabaseService. DeleteWalkEntryAsync((WalkEntries)trailDetails))); } } } }
In the preceding code snippet, we modified our LoadWalkDetails
instance method to check to see if we are already in the middle of processing walk trail items within the ListView
. Then, we proceeded to populate our WalkEntries
array with items retrieved from our GetWalkEntriesAsync
Azure web service instance method call to populate our WalkEntries
asynchronously and use the await
keyword to wait until the Task
completed.
In the next step, we initialized the IsProcessBusy
indicator to false
, to inform our ViewModel that we are no longer processing.
Finally, we created a Command
property within our class that will be used to permanently handle the deletion of the chosen walk entry within our ListView
and our TrackMyWalks
Microsoft Azure database.
In this section, we need to update our WalksPage
ContentPage
so that it can reference the updated changes within our WalksPageViewModel
. We will need to apply additional logic to handle deletions of walk entry information from our WalkEntries
model so that it can retrieve newly updated information from our TrackMyWalks
database located within our Microsoft Azure platform, and display this within the ListView
control.
Let's look at how we can achieve this with following steps:
WalksPage.cs
file is displayed within the code editor, and enter in the following highlighted code sections as shown in the code snippet:// // WalksPage.cs // TrackMyWalks // // Created by Steven F. Daniel on 04/08/2016. // Copyright © 2016 GENIESOFT STUDIOS. All rights reserved. // using Xamarin.Forms; using TrackMyWalks.Models; using TrackMyWalks.ViewModels; using TrackMyWalks.Services; using TrackMyWalks.DataTemplates; using TrackMyWalks.ValueConverters; using System.Diagnostics; namespace TrackMyWalks { public class WalksPage : ContentPage { WalksPageViewModel _viewModel { get { return BindingContext as WalksPageViewModel; } }
newWalkItem
variable, which is within the WalksPage
class constructor and update the Text
property for our ToolbarItem
. Proceed and enter in the following highlighted code sections:public WalksPage() { var newWalkItem = new ToolbarItem { Text = "Add" }; // Set up our Binding click event handler newWalkItem.SetBinding(ToolbarItem.CommandProperty, "CreateNewWalk"); // Add the ToolBar item to our ToolBar ToolbarItems.Add(newWalkItem); // Declare and initialise our Model Binding Context BindingContext = new WalksPageViewModel(DependencyService .Get<IWalkNavService>()); ... ...
walksList.ItemTapped
method whenever an item within the ListView
has been selected. Here, we need to display a selection of choices for the user to choose from, using the DisplayActionSheet
method. When the user chooses the Proceed With
option, the user will be navigated to the WalksTrail
page within our ViewModel, and pass in the item that has been selected. Alternatively, if the user chooses the Delete
button, a call is made to our DeleteWalkItem
command that is included within our WalksPageViewModel
class, so that it can then permanently delete the Walk Entry from our TrackMyWalks
Azure database. Once the walk entry has been deleted from the database, the user will receive a pop-up notification telling them that the item has been deleted. Proceed and enter in the following highlighted code sections:// Initialize our event Handler to use when the // item is tapped walksList.ItemTapped += async (object sender, ItemTappedEventArgs e) => { // Get the selected item by the user var item = (WalkEntries)e.Item; // Check to see if we have a value for our item if (item == null) return; // Display an action sheet with choices var action = await DisplayActionSheet("Track My Walks - Trail Details", "Cancel","Delete", "Proceed With " + item.Title + " Trail"); if (action.Contains("Proceed")) { _viewModel.WalkTrailDetails.Execute(item); } // If we have chosen Delete, delete the item from // our database and refresh the ListView else if (action.Contains("Delete")) { _viewModel.DeleteWalkItem.Execute(item); await DisplayAlert("Track My Walks - Trail Details", item.Title + " has been deleted from the database.", "OK"); await _viewModel.Init(); } // Initialise our item variable to null item = null; }; ... ... } }
In the preceding code snippet, we modified our newWalkItem
variable, which is within the WalksPage
class constructor and updated the Text
property for our ToolbarItem
.
Next, we modified our walksList.ItemTapped
method to handle situations when an item has been selected from the ListView
, which will display a selection of choices for the user to choose from. We accomplished this by using the DisplayActionSheet
method. When the user chooses the Delete
button, a call is made to our DeleteWalkItem
command that is included within our WalksPageViewModel
class, so that it can then permanently delete the walk entry from our TrackMyWalks
Azure database, and use the await
keyword to wait until the Task
has completed before displaying a pop-up notification telling them that the item has been deleted.
Now that we have modified our WalkEntries
database model, we will need to update the DifficultyPickerCellRenderer
class which will be used by our iOS portion of the DifficultyPickerEntryCell
class.
This custom picker will be used to obtain the item chosen from the custom list of entries defined within the DifficultyPicker
class and store this within the Difficulty
property that will then be written to our TrackMyWalks
Microsoft Azure database.
Let's look at how we can achieve this with the following steps:
TrackMyWalks.iOS
project located within our TrackMyWalks
solution, and expand the Renderers
folder.DifficultyPickerCellRenderer.cs
file and ensure that it is displayed within the code editor, and enter in the following highlighted code sections in the code snippet:// // DifficultyPickerCellRenderer.cs // TrackMyWalks CustomRenderer for UIPickerView Entry Cells (iOS) // // Created by Steven F. Daniel on 01/10/2016. // Copyright © 2016 GENIESOFT STUDIOS. All rights reserved. // using Xamarin.Forms.Platform.iOS; using UIKit; using TrackMyWalks.Controls; using Xamarin.Forms; using TrackMyWalks.iOS.Renderers; [assembly: ExportRenderer(typeof( DifficultyPickerEntryCell), typeof(DifficultyPickerCellRenderer))] namespace TrackMyWalks.iOS.Renderers { public class DifficultyPickerCellRenderer : EntryCellRenderer { public override UITableViewCell GetCell( Cell item, UITableViewCell reusableCell, UITableView tv) { var cell = base.GetCell(item, reusableCell, tv); var entryPickerCell = (EntryCell)item; UITextField textField = null; if (cell != null) textField = (UITextField)cell.ContentView.Subviews[0]; // Create our iOS UIPickerView Native Control var difficultyPicker = new UIPickerView { AutoresizingMask = UIViewAutoresizing.FlexibleWidth, ShowSelectionIndicator = true, Model = new DifficultyPickerModel(), BackgroundColor = UIColor.White, };
EntryCellRendererGetCell
method so that it can update the Difficulty
property for the EntryCell
we are currently on when the Done
button has been pressed. It will update it with the value from the difficultyPicker
object and then dismiss the custom picker control. Proceed and enter in the following highlighted code sections:// Create a toolbar with a done button that will // set the selected value when closed. var done = new UIBarButtonItem("Done", UIBarButtonItemStyle.Done, (s, e) => { // Update the Difficulty property on the Cell if (entryPickerCell != null) entryPickerCell.Text = DifficultyPickerModel. difficulty[difficultyPicker. SelectedRowInComponent(0)]; // Update the value of the UITextField within the // Cell if (textField != null) { textField.Text = DifficultyPickerModel.difficulty [difficultyPicker.SelectedRowInComponent(0)]; textField.ResignFirstResponder(); } }); ... ... } } }
Now that we have applied the code changes required to the DifficultyPickerCellRenderer
class for our iOS portion of our TrackMyWalks
app, the next step is to make changes to our WalkEntryContentPage
so that it will retrieve the correct difficulty value that is returned from our custom picker, and the Difficulty
property value.
In the previous section, we modified our DifficultyPickerCellRenderer
class, as well as defining the various methods that will handle the display of the UIPickerView
control when an EntryCell
within the ViewModel has been tapped.
In this section, we'll look at making the necessary code changes required so that our WalkEntryPageContentPage
correctly retrieves the level of difficulty chosen from our custom UIPickerViewDifficultyPickerCellRenderer
class.
Let's look at how we can achieve this with the following steps:
WalkEntryPage.cs
file is displayed within the code editor, and enter in the following highlighted code sections as shown in the code snippet:// // WalkEntryPage.cs // TrackMyWalks // // Created by Steven F. Daniel on 04/08/2016. // Copyright © 2016 GENIESOFT STUDIOS. All rights reserved. // using Xamarin.Forms; using TrackMyWalks.Services; using TrackMyWalks.Controls; namespace TrackMyWalks { public class WalkEntryPage : ContentPage { WalkEntryViewModel _viewModel { get { return BindingContext as WalkEntryViewModel; } } public WalkEntryPage() { // Set the Content Page Title Title = "New Walk Entry"; // Declare and initialise our Model Binding Context BindingContext = new WalkEntryViewModel( DependencyService.Get<IWalkNavService>()); // Define our New Walk Entry fields var walkTitle = new EntryCell { Label = "Title:", Placeholder = "Trail Title" }; walkTitle.SetBinding(EntryCell.TextProperty, "Title", BindingMode.TwoWay); ... ...
walkDifficultyEntryCell
property so that it can correctly return the value of the Difficulty
property from our WalkEntries
ViewModel, that is updated by our DifficultyPickerEntryCell
class. Proceed and enter in the following highlighted code sections:var walkDifficulty = new DifficultyPickerEntryCell { Label = "Difficulty Level:", Placeholder = "Walk Difficulty" }; walkDifficulty.SetBinding(EntryCell.TextProperty, "Difficulty", BindingMode.TwoWay); ... ... } } }
In this section, we looked at the steps involved in modifying our WalkEntryPage
so that it correctly returns the level of difficulty that has been chosen from our DifficultyPickerEntryCell
class custom renderer. We looked at updating our walkDifficulty
object variable to reference the DifficultyPickerEntryCell
class, and updated the setBinding
to return the value of the Difficulty
property that is implemented within the WalkEntries
ViewModel class.
Now that we have finished building all the necessary components for our TrackMyWalks
application, the next step is to finally build and run the TrackMyWalks
application within the iOS simulator. When compilation completes, the iOS Simulator will appear automatically and the TrackMyWalks
application will be displayed, as shown in the following screenshot:
As you can see from the preceding screenshot, this currently displays our ActivityIndicator
spinner control, with the associated Loading Trail Walks... text, after which this will display the ListView
that will contain our list of trail walks from our DataTemplate
control. Since we don't have any walk entries contained within our Microsoft Azure TrackMyWalks
database, the New Walk Entry screen displays entries being entered:
The preceding screenshot, shows the updated ListView
control displaying information from our TrackMyWalks
Microsoft Azure database. You will notice, that upon selecting a Walk entry item from the ListView
control, it will pop up with several choices for you to choose from. If you click on the Delete button, it will call the DeleteWalkEntryAsync
API and pass in the Identifier for the selected item that is to be permanently deleted from the database.
Upon successful deletion, you will be presented with a dialog box telling you that the walk entry has been deleted. When clicking on the OK button, the ListView
control will be refreshed and display all entries, except for the one that you had just deleted. Alternatively, if you click on the Proceed With ... button, it will navigate to the walks Trail Details page where you can begin your trail, by clicking on the Begin this Trail button.
3.138.36.38