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. namespace Covid19Tracker
  7. {
  8. class WebAPI
  9. {
  10. public static Task<HttpResponseMessage> GetCall(string url)
  11. {
  12. try
  13. {
  14. ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
  15. var baseAdress = "https://covid19.mathdro.id/api/";
  16. string apiUrl = baseAdress+url;
  17. using (HttpClient client = new HttpClient())
  18. {
  19. client.BaseAddress = new Uri(baseAdress);
  20. client.Timeout = TimeSpan.FromSeconds(900);
  21. client.DefaultRequestHeaders.Accept.Clear();
  22. client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  23. var response = client.GetAsync(apiUrl);
  24. response.Wait();
  25. return response;
  26. }
  27. }
  28. catch (Exception ex)
  29. {
  30. throw;
  31. }
  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. namespace Covid19Tracker
  3. {
  4. public class Country
  5. {
  6. public string name { get; set; }
  7. public string iso2 { get; set; }
  8. public string iso3 { get; set; }
  9. }
  10. public class Countries
  11. {
  12. public List<Country> countries { get; set; }
  13. }
  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. namespace Covid19Tracker
  7. {
  8. public class MainWindowViewModel : BindableBase
  9. {
  10. #region Properties
  11. private List<ChartData> _chartdetailsList;
  12. public List<ChartData> ChartdetailsList
  13. {
  14. get { return _chartdetailsList; }
  15. set { SetProperty(ref _chartdetailsList, value); }
  16. }
  17. private StatusDetails _covidDetails;
  18. public StatusDetails CovidDetails
  19. {
  20. get { return _covidDetails; }
  21. set { SetProperty(ref _covidDetails, value); }
  22. }
  23. private Country _selectedCountry;
  24. public Country SelectedCountry
  25. {
  26. get { return _selectedCountry; }
  27. set
  28. {
  29. SetProperty(ref _selectedCountry, value);
  30. GetRecoveryAndFatalityRateByCountry(SelectedCountry.name);
  31. }
  32. }
  33. private Countries affectedCountries;
  34. public Countries AffectedCountries
  35. {
  36. get { return affectedCountries; }
  37. set { SetProperty(ref affectedCountries, value); }
  38. }
  39. #endregion
  40. #region Constructor
  41. /// <summary>
  42. /// Constructor
  43. /// </summary>
  44. public MainWindowViewModel()
  45. {
  46. GetAfftectedNumbersFromAPI();
  47. GetRecoveryAndFatalityRate();
  48. }
  49. #endregion
  50. #region Methods
  51. private void GetAfftectedNumbersFromAPI()
  52. {
  53. var covidNumbers = WebAPI.GetCall("");
  54. UpdateRecoveryAndFatalityRate(covidNumbers);
  55. }
  56. private void GetRecoveryAndFatalityRate()
  57. {
  58. var covidCountries = WebAPI.GetCall("countries");
  59. if (covidCountries.Result.StatusCode == System.Net.HttpStatusCode.OK)
  60. {
  61. AffectedCountries = covidCountries.Result.Content.ReadAsAsync<Countries>().Result;
  62. }
  63. }
  64. private void GetRecoveryAndFatalityRateByCountry(string nameOfTheCountry)
  65. {
  66. var countriesRate = WebAPI.GetCall("countries/" + nameOfTheCountry);
  67. UpdateRecoveryAndFatalityRate(countriesRate);
  68. }
  69. private void UpdateRecoveryAndFatalityRate(Task<HttpResponseMessage> response)
  70. {
  71. if (response.Result.StatusCode == System.Net.HttpStatusCode.OK)
  72. {
  73. CovidDetails = response.Result.Content.ReadAsAsync<StatusDetails>().Result; ChartdetailsList = new List<ChartData>()
  74. {
  75. new ChartData("Recovery Rate",CovidDetails.recovered.value, CovidDetails.confirmed.value),
  76. new ChartData("Fatality Rate",CovidDetails.deaths.value, CovidDetails.confirmed.value)
  77. };
  78. }
  79. }
  80. #endregion
  81. }
  82. }
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 @