COVID 19 Tracker With WPF - Part Two

Introduction

 
We recently created a Covid-19 tracker in WPF, you can check that out here.
 
In this article, we will continue the same project, but we will add the following new features to it.
  • Calculating recovery & fatality rate for each country.
  • Calculating Aafected, recovered & death count per country.
  • Creating ComboBox with Material design in WPF.
  • Binding of Combobox in WPF.
  • Reusing the same function to call 'n' number of API calls.
That being said let's go ahead and start coding.
 
First, we are going to update the UI bit.
  • Add Combobox for countries.
  • Move date to the right-hand side.
  • Decorate controls by adding a shadow effect.
After doing all this we can pretty much fetch the result of every affected country in h world,
 
 

Add Combobox for countries

 
This Combobox is a collection of countries that we are fetching from the API. Based on the selected country we will update the UI.
  1. <Grid x:Name="GridlabelCountries"      
  2.                        Grid.RowSpan="2"    
  3.                        Grid.ColumnSpan="2"    
  4.                        Grid.Row="1">    
  5.                        <Rectangle Height="50" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >    
  6.                            <Rectangle.Effect>    
  7.                                <DropShadowEffect BlurRadius="20" Color="#455a64" RenderingBias="Quality" ShadowDepth="1"/>    
  8.                            </Rectangle.Effect>    
  9.                        </Rectangle>    
  10.                        <Grid Margin="25" Height="50">    
  11.                            <Grid     
  12.                                Width="25"     
  13.                                Height="30"     
  14.                                Background="#455a64"     
  15.                                HorizontalAlignment="Left"     
  16.                                VerticalAlignment="Top" Margin="10 0 0 0">    
  17.                                <Grid.Effect>    
  18.                                    <DropShadowEffect BlurRadius="20" Color="#455a64" RenderingBias="Quality" ShadowDepth="1"/>    
  19.                                </Grid.Effect>    
  20.                                <materialUIDesign:PackIcon    
  21.                                    Kind="Map"     
  22.                                    HorizontalAlignment="Center"    
  23.                                    VerticalAlignment="Bottom"    
  24.                                    Margin="5"     
  25.                                    Foreground="White"     
  26.                                    Width="20"     
  27.                                    Height="20"/>    
  28.                            </Grid>    
  29.                            <ComboBox x:Name="ComboBoxCountries"    
  30.                                ItemsSource="{Binding AffectedCountries.countries}"    
  31.                                      Style="{StaticResource MaterialDesignFloatingHintComboBox}"    
  32.                                      SelectedItem="{Binding SelectedCountry}"     
  33.                                      Margin="0 0 0 5"    
  34.                                      DisplayMemberPath="name"    
  35.                                      Width="300"    
  36.                                      VerticalAlignment="Center"    
  37.                                      materialUIDesign:HintAssist.Hint="Select a Country"/>    
  38.                        </Grid>    
  39.                </Grid>    
The followng properties are considered to fill Combobox
  • ItemSource
    Collection of items;  i.e. List of objects, where each object must have DisplayMemberPath & SelectedValuePath properties. For e.g. our DisplayMemberPath is name of the country, & value is iso2: which is short-code dedicated to each country.

  • SelectedItem
    It is the same type of object of our list, specifying which object is currently selected.

A shadow effect to controls

 
Up above in ComboBox's code, you must have seen this effect tag, this tag specifies the style for shadow, one needs to add DropShadowEffect to achieve the same.
Change respected properties as per your requirements.
  1. <Grid.Effect>  
  2.       <DropShadowEffect BlurRadius="20" Color="#455a64" RenderingBias="Quality" ShadowDepth="1"/>  
  3. </Grid.Effect> 

 Fetching Countries Details

 
 Make the following changes in our WebAPI class,
 
 We have to reuse GetCall method, So we are going to make it parameterized, and will pass the desired string from the calling method.
 
 When you want to get details for the entire world: you can use https://covid19.mathdro.id/api/
 
 Now we have added granularity in our project and decided to fetch details of the country so we are going to use https://covid19.mathdro.id/api/countries/India or any other country based on the value selected in ComboBox.
 
 While calling country API we are simply going to pass India as a parameter.
  1. using System;  
  2. using System.Net;  
  3. using System.Net.Http;  
  4. using System.Net.Http.Headers;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace Covid19Tracker  
  8. {  
  9.     class WebAPI  
  10.     {  
  11.         public static Task<HttpResponseMessage> GetCall(string url)  
  12.         {  
  13.             try  
  14.             {  
  15.                 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;  
  16.                 var baseAdress = "https://covid19.mathdro.id/api/";  
  17.                 string apiUrl = baseAdress+url;  
  18.                 using (HttpClient client = new HttpClient())  
  19.                 {  
  20.                     client.BaseAddress = new Uri(baseAdress);  
  21.                     client.Timeout = TimeSpan.FromSeconds(900);  
  22.                     client.DefaultRequestHeaders.Accept.Clear();  
  23.                     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  24.                     var response = client.GetAsync(apiUrl);  
  25.                     response.Wait();  
  26.                     return response;  
  27.                 }  
  28.             }  
  29.             catch (Exception ex)  
  30.             {  
  31.                 throw;  
  32.             }  
  33.         }  
  34.     }  

Class to store countries and detail of each country

 
The country has matching properties as JSON response, and List of Country is specified by Countries object.
  1. using System.Collections.Generic;  
  2.   
  3. namespace Covid19Tracker  
  4. {  
  5.     public class Country  
  6.     {  
  7.         public string name { getset; }  
  8.         public string iso2 { getset; }  
  9.         public string iso3 { getset; }  
  10.     }  
  11.     public class Countries  
  12.     {  
  13.         public List<Country> countries { getset; }  
  14.     }  

MainWindowViewModel
  • It contains new properties that we are binding to our ComboBox
    • ItemSource: AffectedCountries
    • SelectedItem: SelectedCountry
  • The API call to fetch all the countries,. We are going to fill our ItemSource: Method GetRecoveryAndFatalityRate()
  • To update all properties based on selected country: Method GetRecoveryAndFatalityRateByCountry (string nameOfTheCountry)
  • Name of the country is set in setter as soon as we select a country in ComboBox.
    1. public Country SelectedCountry    
    2.        {    
    3.            get { return _selectedCountry; }    
    4.            set    
    5.            {    
    6.                SetProperty(ref _selectedCountry, value);    
    7.                GetRecoveryAndFatalityRateByCountry(SelectedCountry.name);    
    8.            }    
    9.        }    
The whole MainWindowViewModel,
  1. using Covid19Tracker.DTOClasses;  
  2. using Prism.Mvvm;  
  3. using System.Collections.Generic;  
  4. using System.Net.Http;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace Covid19Tracker  
  8. {  
  9.     public class MainWindowViewModel : BindableBase  
  10.     {  
  11.         #region Properties  
  12.         private List<ChartData> _chartdetailsList;  
  13.   
  14.         public List<ChartData> ChartdetailsList  
  15.         {  
  16.             get { return _chartdetailsList; }  
  17.             set { SetProperty(ref _chartdetailsList, value); }  
  18.         }  
  19.   
  20.         private StatusDetails _covidDetails;  
  21.   
  22.         public StatusDetails CovidDetails  
  23.         {  
  24.             get { return _covidDetails; }  
  25.             set { SetProperty(ref _covidDetails, value); }  
  26.         }  
  27.   
  28.         private Country _selectedCountry;  
  29.   
  30.         public Country SelectedCountry  
  31.         {  
  32.             get { return _selectedCountry; }  
  33.             set  
  34.             {  
  35.                 SetProperty(ref _selectedCountry, value);  
  36.                 GetRecoveryAndFatalityRateByCountry(SelectedCountry.name);  
  37.             }  
  38.         }  
  39.   
  40.         private Countries affectedCountries;  
  41.   
  42.         public Countries AffectedCountries  
  43.         {  
  44.             get { return affectedCountries; }  
  45.             set { SetProperty(ref affectedCountries, value); }  
  46.         }  
  47.         #endregion  
  48.  
  49.         #region Constructor  
  50.         /// <summary>  
  51.         /// Constructor  
  52.         /// </summary>  
  53.         public MainWindowViewModel()  
  54.         {  
  55.             GetAfftectedNumbersFromAPI();  
  56.             GetRecoveryAndFatalityRate();  
  57.         }  
  58.         #endregion  
  59.  
  60.         #region Methods  
  61.         private void GetAfftectedNumbersFromAPI()  
  62.         {  
  63.             var covidNumbers = WebAPI.GetCall("");  
  64.             UpdateRecoveryAndFatalityRate(covidNumbers);  
  65.         }  
  66.   
  67.         private void GetRecoveryAndFatalityRate()  
  68.         {  
  69.             var covidCountries = WebAPI.GetCall("countries");  
  70.   
  71.             if (covidCountries.Result.StatusCode == System.Net.HttpStatusCode.OK)  
  72.             {  
  73.                 AffectedCountries = covidCountries.Result.Content.ReadAsAsync<Countries>().Result;  
  74.             }  
  75.         }  
  76.   
  77.         private void GetRecoveryAndFatalityRateByCountry(string nameOfTheCountry)  
  78.         {  
  79.             var countriesRate = WebAPI.GetCall("countries/" + nameOfTheCountry);  
  80.             UpdateRecoveryAndFatalityRate(countriesRate);  
  81.         }  
  82.   
  83.         private void UpdateRecoveryAndFatalityRate(Task<HttpResponseMessage> response)  
  84.         {  
  85.             if (response.Result.StatusCode == System.Net.HttpStatusCode.OK)  
  86.             {  
  87.                 CovidDetails = response.Result.Content.ReadAsAsync<StatusDetails>().Result; ChartdetailsList = new List<ChartData>()  
  88.                 {  
  89.                    new ChartData("Recovery Rate",CovidDetails.recovered.value, CovidDetails.confirmed.value),  
  90.                    new ChartData("Fatality  Rate",CovidDetails.deaths.value, CovidDetails.confirmed.value)  
  91.                 };  
  92.             }  
  93.         }  
  94.         #endregion  
  95.     }  

Now if you run the project, you will be able to see our output like this.
 
 
Wonderful! We have added a few more features in our project.
 
You can download the code from Github.
 

Conclusion


In this article, we learned how to add Combobox in a WPF application with Material design, how to use WebAPI & how to bind ItemSource and other properties to ComboBox.

This offers reusable functions plus much better user experience with more granularity.

I really hope you have come away from this, with a real grasp on how to develop a WPF application.

Thank you all & I wish you all the very best. Keep learning & Keep Coding!.

You can find me @