Creating the DataService API class for the TrackMyWalks app

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:

  1. Create an empty class within the 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.
  2. Then, enter in 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.
  3. Next, ensure that the 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 
            { 
    
  4. Next, we need to modify our 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 
            { 
    
  5. Next, we'll declare two private class properties, _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.
  6. The 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"); 
            } 
    
  7. Next, we'll implement the 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 SendRequestAsyncWalkWebService base-class instance method.
  8. We'll pass in the 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); 
            } 
    
  9. Next, we'll implement the 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.
  10. We'll pass in the 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); 
            } 
    
  11. Next, we'll implement the 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.
  12. We'll then call the 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.

Note

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

GET

This type tells the HttpMethod class protocol that we are ready to request message content over HTTP to retrieve information from our API, and return this information back, based on the representation format specified within the API.

POST

This type tells the HttpMethod class protocol that we want to create a new entry within our table, as specified within our API.

DELETE

This type tells the HttpMethod class protocol that we want to delete an existing entry within our table, as specified within our API.

Note

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.

Updating the WalkBaseViewModel to use our DataService API

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:

  1. Ensure that the 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(); 
                             } 
                       } 
    
  2. Next, we'll create a 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();
                }
            }
    
  3. Then, we'll need to modify the 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.

Updating the WalkEntryViewModel to use our DataService API

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:

  1. Ensure that the 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(); 
                         } 
                    } 
                ... 
                ... 
    
  2. Next, locate and modify the 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; 
    
  3. Then, we'll make a call to our 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.

Updating the WalksPageViewModel to use our DataService API

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:

  1. Ensure that the 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(); 
                           } 
                       } 
                   ... 
                   ... 
    
  2. Next, locate and modify the 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;
    
                }
    
            } 
            ... 
            ... 
    
  3. Then, create the 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.

Updating the WalksPage to use the updated ViewModel

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:

  1. Ensure that the 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; } 
                    } 
    
  2. Next, modify the 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>()); 
             ... 
             ... 
    
  3. Then, we need to modify our 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.

Updating the custom picker renderer class for the iOS platform

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:

  1. Open the TrackMyWalks.iOS project located within our TrackMyWalks solution, and expand the Renderers folder.
  2. Next, select the 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, 
                        }; 
    
  3. Next, we need to modify the 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.

Updating the WalksEntryPage to use the updated custom picker

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:

  1. Ensure that the 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); 
                        ... 
                        ... 
    
  2. Next, locate and modify the 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:

Updating the WalksEntryPage to use the updated custom picker

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:

Updating the WalksEntryPage to use the updated custom picker

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.36.38