Introduction

Hi folks, if you remember, recently I published a website for COVID 19 Tracker with React. How about we explore our strengths in WPF.
Almost everything is different in these 2 projects. They follow different implementation techniques with respect to their technologies.
Let's create a WPF application with an attractive UI. This project is for education purposes only.
I can't attach source code here due to the maximum size limit, but you can directly download it from Github.
Find the following Github repositories for both, and feel free to tag along on Github, leave a star if you like.
Here is a sneak peek:
COVID 19 Tracker With WPF, Material Design And WebAPI

Features of the app:
  • Attractive UI
  • Easy to use
  • Charts & numbers speak more than text
  • Real-time data
Things you will learn in this project:
  • Using a material design with WPF to enhance the user experience
  • Creating styles for a specific page or application-wide
  • Calling Web-API in any C# backed project with a HttpClient
  • Binding ViewModel Properties with View using MVVM architecture.
We will learn each of these steps one by one.
Open Visual Studio & create a new WPF app, Name it as you wish.
First, we are going to add some basic panels.
  1. <Window x:Class="Covid19Tracker.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. xmlns:local="clr-namespace:Covid19Tracker"
  7. mc:Ignorable="d"
  8. Title="Covid19 Tracker" Height="900" Width="1024" ResizeMode="NoResize" WindowStyle="None">
  9. <Grid x:Name="OuterGrid">
  10. <Grid.ColumnDefinitions>
  11. <ColumnDefinition Width="179*"/>
  12. <ColumnDefinition Width="845*"/>
  13. </Grid.ColumnDefinitions>
  14. <Grid.RowDefinitions>
  15. <RowDefinition Height="2*"/>
  16. <RowDefinition Height="43*"/>
  17. </Grid.RowDefinitions>
  18. <Grid x:Name="Header"
  19. Grid.ColumnSpan="2"
  20. Background="#b71c1c">
  21. </Grid>
  22. </Grid>
  23. </Window>
Now, we need the beauty for our project. Let's add Material.Design.
Go to NuGet Package Manager & do the necessary requirements.
COVID 19 Tracker With WPF, Material Design And WebAPI
Now that we have added Material design in your project, we still need to import some of the styles. We can directly add them to App.xaml so that they will be available across the application.
  1. <Application x:Class="Covid19Tracker.App"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:local="clr-namespace:Covid19Tracker"
  5. StartupUri="MainWindow.xaml">
  6. <Application.Resources>
  7. <ResourceDictionary>
  8. <ResourceDictionary.MergedDictionaries>
  9. <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
  10. <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
  11. <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
  12. <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
  13. </ResourceDictionary.MergedDictionaries>
  14. </ResourceDictionary>
  15. </Application.Resources>
  16. </Application>
Now let us begin with looks.
Adding header & a shutdown button.
  1. <Grid x:Name="Header"
  2. Background="{StaticResource HeaderColor}"
  3. Grid.ColumnSpan="2">
  4. <StackPanel x:Name="HeaderStackPanel">
  5. <Button x:Name="ButtonExit"
  6. Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}"
  7. BorderBrush="{x:Null}"
  8. Background="{x:Null}"
  9. HorizontalAlignment="Right"
  10. Foreground="White"
  11. Height="35"
  12. Width="35"
  13. Click="ButtonExit_Click">
  14. <materialUI:PackIcon Kind="Power"/>
  15. </Button>
  16. </StackPanel>
  17. </Grid>
This is the code behind the add ButtonExit_Click method to add following code:
  1. private void ButtonExit_Click(object sender, RoutedEventArgs e)
  2. {
  3. Application.Current.Shutdown();
  4. }
Styles.xaml
Now let's add ResourceDictionary in our project, Simply right-click on project & select ResouceDictionary. Name as a Styles.xaml
This is where we are going to keep all styles.
Note
Add this entry in App.xaml as well.
  1. Styles.xaml<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  3. <!-- Title Style -->
  4. <Style x:Key="TitleTextBlockStyle"
  5. BasedOn="{StaticResource {x:Type TextBlock}}"
  6. TargetType="TextBlock">
  7. <Setter Property="HorizontalAlignment" Value="Right"/>
  8. <Setter Property="FontFamily" Value="Champagne & Limousines"/>
  9. <Setter Property="Margin" Value="5"/>
  10. <Setter Property="VerticalAlignment" Value="Top"/>
  11. <Setter Property="Foreground" Value="Gray"/>
  12. <Setter Property="FontSize" Value="15"/>
  13. </Style>
  14. <!-- Tracker Style -->
  15. <Style x:Key="ScrollThumbs" TargetType="{x:Type Thumb}">
  16. <Setter Property="Template">
  17. <Setter.Value>
  18. <ControlTemplate TargetType="{x:Type Thumb}">
  19. <Grid x:Name="Grid">
  20. <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Fill="Transparent" />
  21. <Border x:Name="Rectangle1" CornerRadius="10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Background="{TemplateBinding Background}" />
  22. </Grid>
  23. <ControlTemplate.Triggers>
  24. <Trigger Property="Tag" Value="Horizontal">
  25. <Setter TargetName="Rectangle1" Property="Width" Value="Auto" />
  26. <Setter TargetName="Rectangle1" Property="Height" Value="7" />
  27. </Trigger>
  28. </ControlTemplate.Triggers>
  29. </ControlTemplate>
  30. </Setter.Value>
  31. </Setter>
  32. </Style>
  33. <!--ScrollBar Style-->
  34. <Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
  35. <Setter Property="Stylus.IsFlicksEnabled" Value="false" />
  36. <Setter Property="Foreground" Value="LightGray" />
  37. <Setter Property="Background" Value="DarkGray" />
  38. <Setter Property="Width" Value="10" />
  39. <Setter Property="Template">
  40. <Setter.Value>
  41. <ControlTemplate TargetType="{x:Type ScrollBar}">
  42. <Grid x:Name="GridTrack"
  43. Background="{x:Null}"
  44. Width="19">
  45. <Track x:Name="TrackScroll"
  46. Grid.Row="0"
  47. IsDirectionReversed="true" Focusable="false">
  48. <Track.Thumb>
  49. <Thumb x:Name="Thumb" Background="{TemplateBinding Foreground}" Style="{DynamicResource ScrollThumbs}" />
  50. </Track.Thumb>
  51. <Track.IncreaseRepeatButton>
  52. <RepeatButton x:Name="PageUp" Command="ScrollBar.PageDownCommand" Opacity="0" Focusable="false" />
  53. </Track.IncreaseRepeatButton>
  54. <Track.DecreaseRepeatButton>
  55. <RepeatButton x:Name="PageDown" Command="ScrollBar.PageUpCommand" Opacity="0" Focusable="false" />
  56. </Track.DecreaseRepeatButton>
  57. </Track>
  58. </Grid>
  59. <ControlTemplate.Triggers>
  60. <Trigger SourceName="Thumb" Property="IsMouseOver" Value="true">
  61. <Setter Value="{DynamicResource ButtonSelectBrush}" TargetName="Thumb" Property="Background" />
  62. </Trigger>
  63. <Trigger SourceName="Thumb" Property="IsDragging" Value="true">
  64. <Setter Value="{DynamicResource DarkBrush}" TargetName="Thumb" Property="Background" />
  65. </Trigger>
  66. <Trigger Property="IsEnabled" Value="false">
  67. <Setter TargetName="Thumb" Property="Visibility" Value="Collapsed" />
  68. </Trigger>
  69. <Trigger Property="Orientation" Value="Horizontal">
  70. <Setter TargetName="GridTrack" Property="LayoutTransform">
  71. <Setter.Value>
  72. <RotateTransform Angle="-90" />
  73. </Setter.Value>
  74. </Setter>
  75. <Setter TargetName="TrackScroll" Property="LayoutTransform">
  76. <Setter.Value>
  77. <RotateTransform Angle="-90" />
  78. </Setter.Value>
  79. </Setter>
  80. <Setter Property="Width" Value="Auto" />
  81. <Setter Property="Height" Value="12" />
  82. <Setter TargetName="Thumb" Property="Tag" Value="Horizontal" />
  83. <Setter TargetName="PageDown" Property="Command" Value="ScrollBar.PageLeftCommand" />
  84. <Setter TargetName="PageUp" Property="Command" Value="ScrollBar.PageRightCommand" />
  85. </Trigger>
  86. </ControlTemplate.Triggers>
  87. </ControlTemplate>
  88. </Setter.Value>
  89. </Setter>
  90. </Style>
  91. </ResourceDictionary>
We have divided our page into 3 sections, header which we already added, now we need...
Left Panel
The left panel is kind of navigation control across your entire application.
  1. <StackPanel x:Name="LeftPanel"
  2. Background="{StaticResource LeftPanelColor}"
  3. Orientation="Vertical"
  4. Grid.Row="1"
  5. Grid.RowSpan="2">
  6. <Grid x:Name="GridLeftPanel">
  7. <TextBlock x:Name="CovidStatus"
  8. FontSize="16"
  9. FontFamily="WS Simple Gallifreyan"
  10. Foreground="#FFBC96EA"
  11. HorizontalAlignment="Center"
  12. Text="Covid-19 Status"
  13. VerticalAlignment="Center" >
  14. </TextBlock>
  15. </Grid>
  16. <Button x:Name="ButtonCovidDashBoard"
  17. Margin="10">
  18. <Grid x:Name="CovidDashBoard"
  19. Height="20"
  20. Width="150">
  21. <materialUIDesign:PackIcon Kind="ViewDashboard"/>
  22. <TextBlock x:Name="TextBlockDASHBOARD"
  23. HorizontalAlignment="Right"
  24. FontFamily="Champagne & Limousines"
  25. Text="DASHBOARD" />
  26. </Grid>
  27. </Button>
  28. <Button Margin="10">
  29. <Grid x:Name="Graph"
  30. Height="20"
  31. Width="150">
  32. <materialUIDesign:PackIcon Kind="ContentPaste"/>
  33. <TextBlock x:Name="TextBlockGRAPH"
  34. FontFamily="Champagne & Limousines"
  35. HorizontalAlignment="Right"
  36. Text="GRAPH" />
  37. </Grid>
  38. </Button>
  39. </StackPanel>
Right Panel
The right panel is where all 3 cards for confirmed, recovered & deaths count will be displayed, Plus the data of the last updated date & our attractive doughnut charts specifying recovery & fatality rate.
  1. <Grid x:Name="RightPanel"
  2. Background="{StaticResource RightPanelColor}"
  3. Grid.Column="1"
  4. Grid.Row="1">
  5. <ScrollViewer>
  6. <Grid>
  7. <Grid.RowDefinitions>
  8. <RowDefinition Height="Auto"/>
  9. <RowDefinition Height="Auto"/>
  10. <RowDefinition Height="Auto"/>
  11. <RowDefinition Height="*"/>
  12. </Grid.RowDefinitions>
  13. <Grid.ColumnDefinitions>
  14. <ColumnDefinition Width="5*"/>
  15. <ColumnDefinition Width="5*"/>
  16. <ColumnDefinition Width="5*"/>
  17. </Grid.ColumnDefinitions>
  18. <Grid x:Name="GridlabelConfirmed"
  19. Grid.Column="0">
  20. <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  21. <Rectangle.Effect>
  22. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  23. </Rectangle.Effect>
  24. </Rectangle>
  25. <Grid Margin="25" Height="120">
  26. <Grid Width="35" Height="50" Background="#ff6f00" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  27. <Grid.Effect>
  28. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  29. </Grid.Effect>
  30. <materialUIDesign:PackIcon Kind="BacteriaOutline" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
  31. </Grid>
  32. <TextBlock x:Name="TextBlockCONFIRMED"
  33. Style="{StaticResource TitleTextBlockStyle}"
  34. Foreground="#ff6f00"
  35. Text="CONFIRMED" />
  36. <StackPanel x:Name="StackPanelMessageTC"
  37. HorizontalAlignment="Right"
  38. Margin="10 30"
  39. Orientation="Horizontal"
  40. VerticalAlignment="Top" >
  41. <materialUIDesign:PackIcon
  42. Foreground="#ff6d00"
  43. Kind="Hope"
  44. Height="15"
  45. Margin="5 0"
  46. VerticalAlignment="Center"
  47. Width="15" />
  48. <TextBlock x:Name="TextBlockTC"
  49. Foreground="#ff6d00"
  50. FontSize="12"
  51. Margin="5 0"
  52. Text="TAKE CARE" />
  53. </StackPanel>
  54. <StackPanel
  55. Orientation="Horizontal"
  56. VerticalAlignment="Bottom"
  57. Margin="20"
  58. Cursor="Hand">
  59. <TextBlock x:Name="TextBlockNumbers"
  60. Text="{Binding CovidDetails.confirmed.value, StringFormat='{}{0:0,0}'}"
  61. FontFamily="Champagne & Limousines"
  62. VerticalAlignment="Center"
  63. Foreground="Gray"
  64. FontSize="30"/>
  65. </StackPanel>
  66. </Grid>
  67. </Grid>
  68. <Grid x:Name="GridlabelRecorvered"
  69. Grid.Column="1">
  70. <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  71. <Rectangle.Effect>
  72. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  73. </Rectangle.Effect>
  74. </Rectangle>
  75. <Grid Margin="25" Height="120">
  76. <Grid Width="35" Height="50" Background="#FF41A43C" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  77. <Grid.Effect>
  78. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  79. </Grid.Effect>
  80. <materialUIDesign:PackIcon Kind="HealthPotion" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
  81. </Grid>
  82. <TextBlock x:Name="TextBlockRECORVERED"
  83. Style="{StaticResource TitleTextBlockStyle}"
  84. Foreground="#FF41A43C"
  85. Text="RECORVERED" />
  86. <StackPanel x:Name="StackPanelMessageSH"
  87. HorizontalAlignment="Right"
  88. Orientation="Horizontal"
  89. Margin="10 30"
  90. VerticalAlignment="Top" >
  91. <materialUIDesign:PackIcon
  92. Kind="Home"
  93. Height="15"
  94. Foreground="#388e3c"
  95. Margin="5 0"
  96. VerticalAlignment="Center"
  97. Width="15" />
  98. <TextBlock
  99. FontSize="12"
  100. Foreground="#388e3c"
  101. Text="STAY HOME" />
  102. </StackPanel>
  103. <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20">
  104. <TextBlock
  105. Text="{Binding CovidDetails.recovered.value,StringFormat='{}{0:0,0}'}"
  106. FontFamily="Champagne & Limousines"
  107. VerticalAlignment="Center"
  108. Foreground="Gray"
  109. FontSize="30"/>
  110. </StackPanel>
  111. </Grid>
  112. </Grid>
  113. <Grid x:Name="GridlabelDeaths"
  114. Grid.Column="2">
  115. <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  116. <Rectangle.Effect>
  117. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  118. </Rectangle.Effect>
  119. </Rectangle>
  120. <Grid Margin="25" Height="120">
  121. <Grid Width="35" Height="50" Background="#FFCF1F1F" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  122. <Grid.Effect>
  123. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  124. </Grid.Effect>
  125. <materialUIDesign:PackIcon Kind="Cross" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
  126. </Grid>
  127. <TextBlock x:Name="TextBlockDEATHS"
  128. Style="{StaticResource TitleTextBlockStyle}"
  129. Foreground="#FFCF1F1F"
  130. Text="DEATHS" />
  131. <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="10 30">
  132. <materialUIDesign:PackIcon
  133. Kind="MedicalBag"
  134. Foreground="#d50000"
  135. Width="15"
  136. Height="15"
  137. VerticalAlignment="Center"
  138. Margin="5 0"/>
  139. <TextBlock
  140. Text="R.I.P."
  141. FontSize="15"
  142. Foreground="#d50000"/>
  143. </StackPanel>
  144. <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20">
  145. <TextBlock
  146. Text="{Binding CovidDetails.deaths.value , StringFormat='{}{0:0,0}'}"
  147. FontFamily="Champagne & Limousines"
  148. VerticalAlignment="Center"
  149. Foreground="Gray"
  150. FontSize="30"/>
  151. </StackPanel>
  152. </Grid>
  153. </Grid>
  154. <Grid x:Name="GridlabelDate"
  155. Grid.RowSpan="2"
  156. Grid.ColumnSpan="3"
  157. Grid.Column="0"
  158. Grid.Row="1">
  159. <Rectangle Height="40" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  160. <Rectangle.Effect>
  161. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  162. </Rectangle.Effect>
  163. </Rectangle>
  164. <Grid Margin="25" Height="40">
  165. <Grid Width="25" Height="30" Background="#311b92" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  166. <Grid.Effect>
  167. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  168. </Grid.Effect>
  169. <materialUIDesign:PackIcon
  170. Kind="Calendar"
  171. HorizontalAlignment="Center"
  172. VerticalAlignment="Bottom"
  173. Margin="5"
  174. Foreground="White"
  175. Width="20"
  176. Height="20"/>
  177. </Grid>
  178. <TextBlock x:Name="TextBlockDATE"
  179. Style="{StaticResource TitleTextBlockStyle}"
  180. Foreground="#311b92"
  181. FontSize="20"
  182. HorizontalAlignment="Left"
  183. Margin="50 5 0 0"
  184. Text="LAST UPDATED DATE" />
  185. <TextBlock
  186. Text="{Binding CovidDetails.lastUpdate}"
  187. FontFamily="Champagne & Limousines"
  188. VerticalAlignment="Center"
  189. Foreground="Gray"
  190. FontSize="20"
  191. Margin="300 5 0 0"/>
  192. </Grid>
  193. </Grid>
  194. <Grid x:Name="GridLabelRatios"
  195. Grid.Row="3"
  196. Grid.RowSpan="2"
  197. Grid.ColumnSpan="3"
  198. HorizontalAlignment="Center"
  199. Width="800"
  200. Height="400">
  201. <Grid
  202. Background="White"
  203. Margin="20 25 15 10">
  204. <Grid.OpacityMask>
  205. <VisualBrush Visual="{ Binding ElementName=BorderG1 }"/>
  206. </Grid.OpacityMask>
  207. <Border x:Name="BorderG1" CornerRadius="5" Background="White" Margin="0,0,0,119"/>
  208. <StackPanel
  209. VerticalAlignment="Bottom" >
  210. <StackPanel
  211. Orientation="Horizontal"
  212. Margin="20 5"/>
  213. <StackPanel
  214. Orientation="Horizontal"
  215. Margin="10 5"/>
  216. </StackPanel>
  217. </Grid>
  218. <Grid Margin="50 0 30 20">
  219. <Grid.OpacityMask>
  220. <VisualBrush Visual="{ Binding ElementName=BorderG2 }"/>
  221. </Grid.OpacityMask>
  222. <Border x:Name="BorderG2" CornerRadius="15" Background="#FF340051"/>
  223. <MetroChart:RadialGaugeChart
  224. Background="{x:Null}"
  225. ChartTitle="Ratio:"
  226. Foreground="LightGray"
  227. Margin="50 0 0 0">
  228. <MetroChart:RadialGaugeChart.Series>
  229. <MetroChart:ChartSeries
  230. DisplayMember="Description"
  231. ItemsSource="{Binding ChartdetailsList}"
  232. SeriesTitle="Description"
  233. ValueMember="Value"
  234. HorizontalAlignment="Center"/>
  235. </MetroChart:RadialGaugeChart.Series>
  236. </MetroChart:RadialGaugeChart>
  237. </Grid>
  238. </Grid>
  239. </Grid>
  240. </ScrollViewer>
  241. </Grid>
Here is the complete screen,
All things combined here.
  1. <Window x:Class="Covid19Tracker.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:materialUIDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  6. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  7. xmlns:MetroChart="clr-namespace:De.TorstenMandelkow.MetroChart;assembly=De.TorstenMandelkow.MetroChart"
  8. mc:Ignorable="d"
  9. Title="Covid19 Tracker" Height="700" Width="1024" WindowStyle="None" WindowStartupLocation="CenterScreen">
  10. <Window.Resources>
  11. <ResourceDictionary>
  12. <SolidColorBrush x:Key="HeaderColor">#512da8</SolidColorBrush>
  13. <SolidColorBrush x:Key="LeftPanelColor">#4a148c</SolidColorBrush>
  14. <SolidColorBrush x:Key="RightPanelColor">#d1c4e9</SolidColorBrush>
  15. </ResourceDictionary>
  16. </Window.Resources>
  17. <Grid x:Name="OuterGrid">
  18. <Grid.ColumnDefinitions>
  19. <ColumnDefinition Width="2*"/>
  20. <ColumnDefinition Width="8*"/>
  21. </Grid.ColumnDefinitions>
  22. <Grid.RowDefinitions>
  23. <RowDefinition Height="Auto"/>
  24. <RowDefinition Height="*"/>
  25. </Grid.RowDefinitions>
  26. <Grid x:Name="Header"
  27. Background="{StaticResource HeaderColor}"
  28. Grid.ColumnSpan="2">
  29. <StackPanel x:Name="HeaderStackPanel">
  30. <Button x:Name="ButtonExit"
  31. Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}"
  32. BorderBrush="{x:Null}"
  33. Background="{x:Null}"
  34. Click="ButtonExit_Click"
  35. Foreground="White"
  36. Height="35"
  37. HorizontalAlignment="Right"
  38. VerticalAlignment="Top"
  39. Width="35">
  40. <materialUIDesign:PackIcon Kind="Power"/>
  41. </Button>
  42. </StackPanel>
  43. </Grid>
  44. <StackPanel x:Name="LeftPanel"
  45. Background="{StaticResource LeftPanelColor}"
  46. Orientation="Vertical"
  47. Grid.Row="1"
  48. Grid.RowSpan="2">
  49. <Grid x:Name="GridLeftPanel">
  50. <TextBlock x:Name="CovidStatus"
  51. FontSize="16"
  52. FontFamily="WS Simple Gallifreyan"
  53. Foreground="#FFBC96EA"
  54. HorizontalAlignment="Center"
  55. Text="Covid-19 Status"
  56. VerticalAlignment="Center" >
  57. </TextBlock>
  58. </Grid>
  59. <Button x:Name="ButtonCovidDashBoard"
  60. Margin="10">
  61. <Grid x:Name="CovidDashBoard"
  62. Height="20"
  63. Width="150">
  64. <materialUIDesign:PackIcon Kind="ViewDashboard"/>
  65. <TextBlock x:Name="TextBlockDASHBOARD"
  66. HorizontalAlignment="Right"
  67. FontFamily="Champagne & Limousines"
  68. Text="DASHBOARD" />
  69. </Grid>
  70. </Button>
  71. <Button Margin="10">
  72. <Grid x:Name="Graph"
  73. Height="20"
  74. Width="150">
  75. <materialUIDesign:PackIcon Kind="ContentPaste"/>
  76. <TextBlock x:Name="TextBlockGRAPH"
  77. FontFamily="Champagne & Limousines"
  78. HorizontalAlignment="Right"
  79. Text="GRAPH" />
  80. </Grid>
  81. </Button>
  82. </StackPanel>
  83. <Grid x:Name="RightPanel"
  84. Background="{StaticResource RightPanelColor}"
  85. Grid.Column="1"
  86. Grid.Row="1">
  87. <ScrollViewer>
  88. <Grid>
  89. <Grid.RowDefinitions>
  90. <RowDefinition Height="Auto"/>
  91. <RowDefinition Height="Auto"/>
  92. <RowDefinition Height="Auto"/>
  93. <RowDefinition Height="*"/>
  94. </Grid.RowDefinitions>
  95. <Grid.ColumnDefinitions>
  96. <ColumnDefinition Width="5*"/>
  97. <ColumnDefinition Width="5*"/>
  98. <ColumnDefinition Width="5*"/>
  99. </Grid.ColumnDefinitions>
  100. <Grid x:Name="GridlabelConfirmed"
  101. Grid.Column="0">
  102. <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  103. <Rectangle.Effect>
  104. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  105. </Rectangle.Effect>
  106. </Rectangle>
  107. <Grid Margin="25" Height="120">
  108. <Grid Width="35" Height="50" Background="#ff6f00" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  109. <Grid.Effect>
  110. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  111. </Grid.Effect>
  112. <materialUIDesign:PackIcon Kind="BacteriaOutline" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
  113. </Grid>
  114. <TextBlock x:Name="TextBlockCONFIRMED"
  115. Style="{StaticResource TitleTextBlockStyle}"
  116. Foreground="#ff6f00"
  117. Text="CONFIRMED" />
  118. <StackPanel x:Name="StackPanelMessageTC"
  119. HorizontalAlignment="Right"
  120. Margin="10 30"
  121. Orientation="Horizontal"
  122. VerticalAlignment="Top" >
  123. <materialUIDesign:PackIcon
  124. Foreground="#ff6d00"
  125. Kind="Hope"
  126. Height="15"
  127. Margin="5 0"
  128. VerticalAlignment="Center"
  129. Width="15" />
  130. <TextBlock x:Name="TextBlockTC"
  131. Foreground="#ff6d00"
  132. FontSize="12"
  133. Margin="5 0"
  134. Text="TAKE CARE" />
  135. </StackPanel>
  136. <StackPanel
  137. Orientation="Horizontal"
  138. VerticalAlignment="Bottom"
  139. Margin="20"
  140. Cursor="Hand">
  141. <TextBlock x:Name="TextBlockNumbers"
  142. Text="{Binding CovidDetails.confirmed.value, StringFormat='{}{0:0,0}'}"
  143. FontFamily="Champagne & Limousines"
  144. VerticalAlignment="Center"
  145. Foreground="Gray"
  146. FontSize="30"/>
  147. </StackPanel>
  148. </Grid>
  149. </Grid>
  150. <Grid x:Name="GridlabelRecorvered"
  151. Grid.Column="1">
  152. <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  153. <Rectangle.Effect>
  154. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  155. </Rectangle.Effect>
  156. </Rectangle>
  157. <Grid Margin="25" Height="120">
  158. <Grid Width="35" Height="50" Background="#FF41A43C" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  159. <Grid.Effect>
  160. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  161. </Grid.Effect>
  162. <materialUIDesign:PackIcon Kind="HealthPotion" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
  163. </Grid>
  164. <TextBlock x:Name="TextBlockRECORVERED"
  165. Style="{StaticResource TitleTextBlockStyle}"
  166. Foreground="#FF41A43C"
  167. Text="RECORVERED" />
  168. <StackPanel x:Name="StackPanelMessageSH"
  169. HorizontalAlignment="Right"
  170. Orientation="Horizontal"
  171. Margin="10 30"
  172. VerticalAlignment="Top" >
  173. <materialUIDesign:PackIcon
  174. Kind="Home"
  175. Height="15"
  176. Foreground="#388e3c"
  177. Margin="5 0"
  178. VerticalAlignment="Center"
  179. Width="15" />
  180. <TextBlock
  181. FontSize="12"
  182. Foreground="#388e3c"
  183. Text="STAY HOME" />
  184. </StackPanel>
  185. <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20">
  186. <TextBlock
  187. Text="{Binding CovidDetails.recovered.value,StringFormat='{}{0:0,0}'}"
  188. FontFamily="Champagne & Limousines"
  189. VerticalAlignment="Center"
  190. Foreground="Gray"
  191. FontSize="30"/>
  192. </StackPanel>
  193. </Grid>
  194. </Grid>
  195. <Grid x:Name="GridlabelDeaths"
  196. Grid.Column="2">
  197. <Rectangle Height="120" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  198. <Rectangle.Effect>
  199. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  200. </Rectangle.Effect>
  201. </Rectangle>
  202. <Grid Margin="25" Height="120">
  203. <Grid Width="35" Height="50" Background="#FFCF1F1F" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  204. <Grid.Effect>
  205. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  206. </Grid.Effect>
  207. <materialUIDesign:PackIcon Kind="Cross" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5" Foreground="White" Width="20" Height="20"/>
  208. </Grid>
  209. <TextBlock x:Name="TextBlockDEATHS"
  210. Style="{StaticResource TitleTextBlockStyle}"
  211. Foreground="#FFCF1F1F"
  212. Text="DEATHS" />
  213. <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="10 30">
  214. <materialUIDesign:PackIcon
  215. Kind="MedicalBag"
  216. Foreground="#d50000"
  217. Width="15"
  218. Height="15"
  219. VerticalAlignment="Center"
  220. Margin="5 0"/>
  221. <TextBlock
  222. Text="R.I.P."
  223. FontSize="15"
  224. Foreground="#d50000"/>
  225. </StackPanel>
  226. <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="20">
  227. <TextBlock
  228. Text="{Binding CovidDetails.deaths.value , StringFormat='{}{0:0,0}'}"
  229. FontFamily="Champagne & Limousines"
  230. VerticalAlignment="Center"
  231. Foreground="Gray"
  232. FontSize="30"/>
  233. </StackPanel>
  234. </Grid>
  235. </Grid>
  236. <Grid x:Name="GridlabelDate"
  237. Grid.RowSpan="2"
  238. Grid.ColumnSpan="3"
  239. Grid.Column="0"
  240. Grid.Row="1">
  241. <Rectangle Height="40" Margin="20" Fill="White" RadiusY="10" RadiusX="10" >
  242. <Rectangle.Effect>
  243. <DropShadowEffect BlurRadius="20" Color="#FFDEDEDE" RenderingBias="Quality" ShadowDepth="1"/>
  244. </Rectangle.Effect>
  245. </Rectangle>
  246. <Grid Margin="25" Height="40">
  247. <Grid Width="25" Height="30" Background="#311b92" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20 0">
  248. <Grid.Effect>
  249. <DropShadowEffect BlurRadius="20" Color="#FFECECEC" RenderingBias="Quality" ShadowDepth="1"/>
  250. </Grid.Effect>
  251. <materialUIDesign:PackIcon
  252. Kind="Calendar"
  253. HorizontalAlignment="Center"
  254. VerticalAlignment="Bottom"
  255. Margin="5"
  256. Foreground="White"
  257. Width="20"
  258. Height="20"/>
  259. </Grid>
  260. <TextBlock x:Name="TextBlockDATE"
  261. Style="{StaticResource TitleTextBlockStyle}"
  262. Foreground="#311b92"
  263. FontSize="20"
  264. HorizontalAlignment="Left"
  265. Margin="50 5 0 0"
  266. Text="LAST UPDATED DATE" />
  267. <TextBlock
  268. Text="{Binding CovidDetails.lastUpdate}"
  269. FontFamily="Champagne & Limousines"
  270. VerticalAlignment="Center"
  271. Foreground="Gray"
  272. FontSize="20"
  273. Margin="300 5 0 0"/>
  274. </Grid>
  275. </Grid>
  276. <Grid x:Name="GridLabelRatios"
  277. Grid.Row="3"
  278. Grid.RowSpan="2"
  279. Grid.ColumnSpan="3"
  280. HorizontalAlignment="Center"
  281. Width="800"
  282. Height="400">
  283. <Grid
  284. Background="White"
  285. Margin="20 25 15 10">
  286. <Grid.OpacityMask>
  287. <VisualBrush Visual="{ Binding ElementName=BorderG1 }"/>
  288. </Grid.OpacityMask>
  289. <Border x:Name="BorderG1" CornerRadius="5" Background="White" Margin="0,0,0,119"/>
  290. <StackPanel
  291. VerticalAlignment="Bottom" >
  292. <StackPanel
  293. Orientation="Horizontal"
  294. Margin="20 5"/>
  295. <StackPanel
  296. Orientation="Horizontal"
  297. Margin="10 5"/>
  298. </StackPanel>
  299. </Grid>
  300. <Grid Margin="50 0 30 20">
  301. <Grid.OpacityMask>
  302. <VisualBrush Visual="{ Binding ElementName=BorderG2 }"/>
  303. </Grid.OpacityMask>
  304. <Border x:Name="BorderG2" CornerRadius="15" Background="#FF340051"/>
  305. <MetroChart:RadialGaugeChart
  306. Background="{x:Null}"
  307. ChartTitle="Ratio:"
  308. Foreground="LightGray"
  309. Margin="50 0 0 0">
  310. <MetroChart:RadialGaugeChart.Series>
  311. <MetroChart:ChartSeries
  312. DisplayMember="Description"
  313. ItemsSource="{Binding ChartdetailsList}"
  314. SeriesTitle="Description"
  315. ValueMember="Value"
  316. HorizontalAlignment="Center"/>
  317. </MetroChart:RadialGaugeChart.Series>
  318. </MetroChart:RadialGaugeChart>
  319. </Grid>
  320. </Grid>
  321. </Grid>
  322. </ScrollViewer>
  323. </Grid>
  324. </Grid>
  325. </Window>
Now that we are done with designing a UI, Let's move further ahead and add that API class in your project:
class WebAPI
We are going to use WebAPI class to make a call to API, For now, we are only using the get method.
This class is responsible for getting our data.
  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()
  11. {
  12. try
  13. {
  14. ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
  15. var baseAdress = "https://covid19.mathdro.id/api";
  16. string apiUrl = baseAdress;
  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. }
Of course, we are going to follow MVVM architecture. Let's add DataContext for our MainWindow.xaml.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Documents;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. using System.Windows.Navigation;
  14. using System.Windows.Shapes;
  15. namespace Covid19Tracker
  16. {
  17. /// <summary>
  18. /// Interaction logic for MainWindow.xaml
  19. /// </summary>
  20. public partial class MainWindow : Window
  21. {
  22. public MainWindow()
  23. {
  24. InitializeComponent();
  25. this.DataContext = new MainWindowViewModel();
  26. }
  27. private void ButtonExit_Click(object sender, RoutedEventArgs e)
  28. {
  29. Application.Current.Shutdown();
  30. }
  31. }
  32. }
class StatusDetails
StatusDetails is responsible for storing our API's response. We need to have the same property name as the JSON response that we get from our API.
For now, we are concerned about 4 specific properties:
  • Confirmed
    class to represent nested JSON object
  • Recovered
    class to represent nested JSON object
  • Deaths
    class to represent nested JSON object
  • LastUpdate
    DateTime to represent the nested date
    1. using System;
    2. namespace Covid19Tracker
    3. {
    4. public class StatusDetails
    5. {
    6. #region Properties
    7. public ConfirmedCases confirmed { get; set; }
    8. public RecoveredCases recovered { get; set; }
    9. public Deaths deaths { get; set; }
    10. public DateTime lastUpdate { get; set; }
    11. #endregion
    12. #region Constructor
    13. public StatusDetails()
    14. {
    15. }
    16. #endregion
    17. #region Internal classes
    18. public class ConfirmedCases
    19. {
    20. public long value { get; set; }
    21. }
    22. public class RecoveredCases
    23. {
    24. public long value { get; set; }
    25. }
    26. public class Deaths
    27. {
    28. public long value { get; set; }
    29. }
    30. public class DailySummary
    31. {
    32. public long value { get; set; }
    33. }
    34. #endregion
    35. }
    36. }
MainViewModel
This class acts as a controller. This is where your UI gets its data & functionalities.
  1. using Covid19Tracker.DTOClasses;
  2. using Prism.Mvvm;
  3. using System.Collections.Generic;
  4. using System.Net.Http;
  5. namespace Covid19Tracker
  6. {
  7. public class MainWindowViewModel : BindableBase
  8. {
  9. private StatusDetails _covidDetails;
  10. public StatusDetails CovidDetails
  11. {
  12. get { return _covidDetails; }
  13. set { SetProperty(ref _covidDetails , value); }
  14. }
  15. public MainWindowViewModel()
  16. {
  17. var response = WebAPI.GetCall();
  18. if (response.Result.StatusCode == System.Net.HttpStatusCode.OK)
  19. {
  20. CovidDetails = response.Result.Content.ReadAsAsync<StatusDetails>().Result;
  21. }
  22. }
  23. }
  24. }
Well, that's just beautiful. Hold on though, we are still missing something.
We forgot to add Itemsource for our Doughnut charts!
The doughnut is partitioned based on numbers and every number has its description associated with it, We need to have a class who can fulfill these needs.
class ChartData
We are going bind 2 properties of this class:
  • Description
    It shows if the doughnut is showing a recovery rate or fatality rate.

  • Value
    It is calculated based on the parameter that we will pass from our ViewModel. This value not only describes the recovery rate but also the fatality rate.
    1. namespace Covid19Tracker.DTOClasses
    2. {
    3. public class ChartData
    4. {
    5. #region Properties
    6. public string Description { get; set; }
    7. public decimal Value { get; set; }
    8. public decimal ConfirmedCases { get; set; }
    9. public decimal RecorveredOrDeaths { get; set; }
    10. #endregion
    11. #region Constructor
    12. public ChartData(string description, decimal recorveredOrDeaths, decimal confirmedCases)
    13. {
    14. this.Description = description;
    15. this.RecorveredOrDeaths = recorveredOrDeaths;
    16. this.ConfirmedCases = confirmedCases;
    17. Value = CalculateFatalityOrRecoveryPercentage();
    18. }
    19. #endregion
    20. #region Methods
    21. private decimal CalculateFatalityOrRecoveryPercentage()
    22. {
    23. return (RecorveredOrDeaths / ConfirmedCases) * 100;
    24. }
    25. #endregion
    26. }
    27. }
Finished MainWindowViewModel
We are sending numbers that we received from API to doughnut chart to calculate the recovery & fatality rate:
  1. using Covid19Tracker.DTOClasses;
  2. using Prism.Mvvm;
  3. using System.Collections.Generic;
  4. using System.Net.Http;
  5. namespace Covid19Tracker
  6. {
  7. public class MainWindowViewModel : BindableBase
  8. {
  9. private List<ChartData> _chartdetailsList;
  10. public List<ChartData> ChartdetailsList
  11. {
  12. get { return _chartdetailsList; }
  13. set { SetProperty(ref _chartdetailsList , value); }
  14. }
  15. private StatusDetails _covidDetails;
  16. public StatusDetails CovidDetails
  17. {
  18. get { return _covidDetails; }
  19. set { SetProperty(ref _covidDetails , value); }
  20. }
  21. public MainWindowViewModel()
  22. {
  23. var response = WebAPI.GetCall();
  24. if (response.Result.StatusCode == System.Net.HttpStatusCode.OK)
  25. {
  26. CovidDetails = response.Result.Content.ReadAsAsync<StatusDetails>().Result;
  27. ChartdetailsList = new List<ChartData>()
  28. {
  29. new ChartData("Recovery Rate",CovidDetails.recovered.value, CovidDetails.confirmed.value),
  30. new ChartData("Fatality Rate",CovidDetails.deaths.value, CovidDetails.confirmed.value)
  31. };
  32. }
  33. }
  34. }
  35. }
Very well done, guys!
So far so good. Now just hit that Start button & embrace the happiness of successfully implementing Covid-19 tracker with WPF & Material design.
Here is the final outcome of your hard work:
COVID 19 Tracker With WPF, Material Design And WebAPI
We are not done yet, in the future, we will update our left panel and add more screens on the right panel.
This is going to be a good project if you desire to learn WPF.

Conclusion

In this article, we learned how to develop a WPF application with Material design and how to use WebAPI & How to bind properties to UI.
It features reusable styles plus a smooth user experience.
I really hope you have come away from this with a real grasp on how to develop a WPF application.
Thank you all, and I wish you the very best. Keep Learning & Keep Coding!
You can find me @