REST API's Implementation In WPF Using Entity Framework

Introduction

 
Greetings all, I trust you're all doing well during this pandemic. Stay safe.
 
The goal of this article is to implement REST APIs operations in WPF.
 
Following is a list that we are going to focus on for UI decoration:
  • How to call the REST API from C#. With respect to all 4 interfaces: Get, Post, Put & Delete
  • Editable DataGrid in WPF
  • Command binding for buttons & Property bindings in WPF
  • Usage of BooleanToVisibility convertor in WPF
  • Run multiple projects in .Net: the first one would be REST API server's project & another is a Client - The WPF application

    Note
    This is part 3 of Rest API implementation with WPF & EF.
If your focus is only to learn REST API's integration with WPF, then you can skip this below listing. However, I highly recommend going through this list of prerequisites.
Now that you've done that, let's move on with our objective. We are going to focus on the middle layer from the following architecture. The presentation Layer of course.

 
To do that, Right-click on solution => add new Project & then select WPF application.
 
I have divided this article into 3 subparts:
  • The REST API integration in C#
  • The ViewModel with all commands, properties & methods
  • Last, the View to display the REST API operations.
The REST API integration in C#
 
We need to have a class for 4 interfaces, Get, Post, Put & Delete.
 
Right-click on the WPF project & click on an add new class option. Then name it WebAPI
 
First, we are going to add the Get method: 
  • Open connection using HttpClient class
  • Add parameters as specified below
  • Add the GetAsync method
  • Wait till the client gets a response
  • The return type is Task
  1. class WebAPI  
  2.   {  
  3.       /// <summary>  
  4.       /// Get employee details  
  5.       /// </summary>  
  6.       /// <param name="url"></param>  
  7.       /// <returns></returns>  
  8.       public static Task<HttpResponseMessage> GetCall(string url)  
  9.       {  
  10.           try  
  11.           {  
  12.               ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;  
  13.               string apiUrl = API_URIs.baseURI + url;  
  14.               using (HttpClient client = new HttpClient())  
  15.               {  
  16.                   client.BaseAddress = new Uri(apiUrl);  
  17.                   client.Timeout = TimeSpan.FromSeconds(900);  
  18.                   client.DefaultRequestHeaders.Accept.Clear();  
  19.                   client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  20.                   var response = client.GetAsync(apiUrl);  
  21.                   response.Wait();  
  22.                   return response;  
  23.               }  
  24.           }  
  25.           catch (Exception ex)  
  26.           {  
  27.               throw;  
  28.           }  
  29.       } 
 Second, the Post method,
  •  The post method has one extra parameter -- T model (T is generic). It represents the data of new Employee which we are supposed to add.

    • We are going to keep that parameter generic because this Post method could be used by 'n' number of clients.

  • Call PostAsJsonAsync method of HttpClient
  1. /// <summary>  
  2. /// creates a new employee  
  3. /// </summary>  
  4. /// <typeparam name="T"></typeparam>  
  5. /// <param name="url"></param>  
  6. /// <param name="model"></param>  
  7. /// <returns></returns>  
  8. public static Task<HttpResponseMessage> PostCall<T>(string url, T model) where T : class  
  9. {  
  10.     try  
  11.     {  
  12.         ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;  
  13.         string apiUrl = API_URIs.baseURI + url;  
  14.         using (HttpClient client = new HttpClient())  
  15.         {  
  16.             client.BaseAddress = new Uri(apiUrl);  
  17.             client.Timeout = TimeSpan.FromSeconds(900);  
  18.             client.DefaultRequestHeaders.Accept.Clear();  
  19.             client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  20.             var response = client.PostAsJsonAsync(apiUrl, model);  
  21.             response.Wait();  
  22.             return response;  
  23.         }  
  24.     }  
  25.     catch (Exception ex)  
  26.     {  
  27.         throw;  
  28.     }  
  29. }  
Third, the Put method.
  • Put method has 2 parameters as well. One is URI & the other is the model to be updated
  • We are going to send the ID of an employee in URI itself.
  • Call PutAsJsonAsync method of HttpClient
  1.        /// <summary>  
  2.        /// Updates emplyees details  
  3.        /// </summary>  
  4.        /// <typeparam name="T"></typeparam>  
  5.        /// <param name="url"></param>  
  6.        /// <param name="model"></param>  
  7.        /// <returns></returns>  
  8.        public static Task<HttpResponseMessage> PutCall<T>(string url, T model) where T : class  
  9.        {  
  10.            try  
  11.            {  
  12.                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;  
  13.                string apiUrl = API_URIs.baseURI + url;  
  14.                using (HttpClient client = new HttpClient())  
  15.                {  
  16.                    client.BaseAddress = new Uri(apiUrl);  
  17.                    client.Timeout = TimeSpan.FromSeconds(900);  
  18.                    client.DefaultRequestHeaders.Accept.Clear();  
  19.                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  20.                    var response = client.PutAsJsonAsync(apiUrl, model);  
  21.                    response.Wait();  
  22.                    return response;  
  23.                }  
  24.            }  
  25.            catch (Exception ex)  
  26.            {  
  27.                throw;  
  28.            }  
  29.        }  
Finally, the Delete method.
  • We are going to concatenate the ID of an employee to be deleted in URI itself. But it is a better practice to keep it separate.
  • Call DeleteAsync method of HttpClient
  1.        /// <summary>  
  2.        /// Delete employee's record  
  3.        /// </summary>  
  4.        /// <param name="url"></param>  
  5.        /// <returns></returns>  
  6.        public static Task<HttpResponseMessage> DeleteCall(string url)   
  7.        {  
  8.            try  
  9.            {  
  10.                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;  
  11.                string apiUrl = API_URIs.baseURI + url;  
  12.                using (HttpClient client = new HttpClient())  
  13.                {  
  14.                    client.BaseAddress = new Uri(apiUrl);  
  15.                    client.Timeout = TimeSpan.FromSeconds(900);  
  16.                    client.DefaultRequestHeaders.Accept.Clear();  
  17.                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));  
  18.                    var response = client.DeleteAsync(apiUrl);  
  19.                    response.Wait();  
  20.                    return response;  
  21.                }  
  22.            }  
  23.            catch (Exception ex)  
  24.            {  
  25.                throw;  
  26.            }  
  27.        } 
Now that you've done that, we can move forward with the 2nd phase of this article, which is:
 
ViewModel
 
Let me give you a tour of MainWindowViewModel. 
  •  Commands

    • GetButtonClicked: Get Method call, Get all the employee's details
    • PostButtonClicked: Creates a new employee
    • PutButtonClicked: Updates an existing employee's record
    • DeleteButtonClicked: Delete an existing employee's record
    • ShowRegistrationForm: Shows form for employee's registration

  • Constructor
    To initialize these commands

  • Properties

    • List of Employees: stores employee's details that we fetch from the get command above.
    • SelectedEmployee: this represents the selected record from Datagrid in view
    • boolean IsLoadData: it sets true after we are finished with fetching all the records.
    • Registration form properties

      • FirstName: get's a value from TextBox FirstName
      • LastName: get's a value from TextBox LastName
      • Gender: get's a value from TextBox Gender
      • Salary: get's a value from TextBox Salary
      • IsShowForm: sets true when "Button-Register Employee" click
      • ShowPostMessage
class MainWindowViewModel,
  1. using A.Utilities;  
  2. using DataAccessLayer;  
  3. using Prism.Commands;  
  4. using Prism.Mvvm;  
  5. using System.Collections.Generic;  
  6. using System.ComponentModel;  
  7. using System.Net.Http;  
  8.   
  9. namespace A  
  10. {  
  11.     class MainWindowViewModel : BindableBase, INotifyPropertyChanged  
  12.     {  
  13.         #region Properties  
  14.   
  15.         private List<Employee> _employees;  
  16.   
  17.         public List<Employee> Employees  
  18.         {  
  19.             get { return _employees; }  
  20.             set {SetProperty(ref _employees, value); }  
  21.         }  
  22.   
  23.         private Employee _selectedEmployee;  
  24.   
  25.         public Employee SelectedEmployee  
  26.         {  
  27.             get { return _selectedEmployee; }  
  28.             set { SetProperty(ref _selectedEmployee, value); }  
  29.         }  
  30.   
  31.         private bool _isLoadData;  
  32.   
  33.         public bool IsLoadData  
  34.         {  
  35.             get { return _isLoadData; }  
  36.             set { SetProperty(ref _isLoadData, value); }  
  37.         }  
  38.   
  39.         private string _responseMessage = "Welcome to REST API Tutorials";  
  40.   
  41.         public string ResponseMessage  
  42.         {  
  43.             get { return _responseMessage; }  
  44.             set { SetProperty(ref _responseMessage , value); }  
  45.         }  
  46.  
  47.         #region [Create Employee Properties]  
  48.   
  49.         private string _firstName;  
  50.   
  51.         public string FirstName  
  52.         {  
  53.             get { return _firstName; }  
  54.             set { SetProperty(ref _firstName, value); }  
  55.         }  
  56.   
  57.   
  58.         private string _lastName;  
  59.   
  60.         public string LastName  
  61.         {  
  62.             get { return _lastName; }  
  63.             set { SetProperty(ref _lastName, value); }  
  64.         }  
  65.   
  66.         private string _gender;  
  67.   
  68.         public string Gender  
  69.         {  
  70.             get { return _gender; }  
  71.             set { SetProperty(ref _gender, value); }  
  72.         }  
  73.   
  74.         private int _salary;  
  75.   
  76.         public int Salary  
  77.         {  
  78.             get { return _salary; }  
  79.             set { SetProperty(ref _salary, value); }  
  80.         }  
  81.         #endregion  
  82.         private bool _isShowForm;  
  83.   
  84.         public bool IsShowForm  
  85.         {  
  86.             get { return _isShowForm; }  
  87.             set { SetProperty(ref _isShowForm, value); }  
  88.         }  
  89.   
  90.         private string _showPostMessage = "Fill the form to register an employee!";  
  91.   
  92.         public string ShowPostMessage  
  93.         {  
  94.             get { return _showPostMessage; }  
  95.             set { SetProperty(ref _showPostMessage, value); }  
  96.         }  
  97.         #endregion  
  98.  
  99.         #region ICommands  
  100.         public DelegateCommand GetButtonClicked { getset; }  
  101.         public DelegateCommand ShowRegistrationForm { getset; }  
  102.         public DelegateCommand PostButtonClick { getset; }  
  103.         public DelegateCommand<Employee> PutButtonClicked { getset; }  
  104.         public DelegateCommand<Employee> DeleteButtonClicked { getset; }  
  105.         #endregion  
  106.  
  107.         #region Constructor  
  108.         /// <summary>  
  109.         /// Initalize perperies & delegate commands  
  110.         /// </summary>  
  111.         public MainWindowViewModel()  
  112.         {  
  113.             GetButtonClicked = new DelegateCommand(GetEmployeeDetails);  
  114.             PutButtonClicked = new DelegateCommand<Employee>(UpdateEmployeeDetails);  
  115.             DeleteButtonClicked = new DelegateCommand<Employee>(DeleteEmployeeDetails);  
  116.             PostButtonClick = new DelegateCommand(CreateNewEmployee);  
  117.             ShowRegistrationForm = new DelegateCommand(RegisterEmployee);  
  118.          }  
  119.         #endregion  
  120.  
  121.         #region CRUD  
  122.         /// <summary>  
  123.         /// Make visible Regiter user form  
  124.         /// </summary>  
  125.         private void RegisterEmployee()  
  126.         {  
  127.             IsShowForm = true;  
  128.         }  
  129.   
  130.         /// <summary>  
  131.         /// Fetches employee details  
  132.         /// </summary>  
  133.         private void GetEmployeeDetails()  
  134.         {  
  135.             var employeeDetails = WebAPI.GetCall(API_URIs.employees);  
  136.             if (employeeDetails.Result.StatusCode == System.Net.HttpStatusCode.OK)  
  137.             {  
  138.                 Employees = employeeDetails.Result.Content.ReadAsAsync<List<Employee>>().Result;  
  139.                 IsLoadData = true;  
  140.             }  
  141.         }  
  142.   
  143.         /// <summary>  
  144.         /// Adds new employee  
  145.         /// </summary>  
  146.         private void CreateNewEmployee()  
  147.         {  
  148.             Employee newEmployee = new Employee()  
  149.             {  
  150.                 FirstName = FirstName,  
  151.                 LastName = LastName,  
  152.                 Gender = Gender,  
  153.                 Salary = Salary  
  154.             };  
  155.             var employeeDetails = WebAPI.PostCall(API_URIs.employees, newEmployee);  
  156.             if (employeeDetails.Result.StatusCode == System.Net.HttpStatusCode.Created)  
  157.             {  
  158.                 ShowPostMessage = newEmployee.FirstName + "'s details has successfully been added!";  
  159.             }  
  160.             else  
  161.             {  
  162.                 ShowPostMessage = "Failed to update" + newEmployee.FirstName + "'s details.";  
  163.             }  
  164.         }  
  165.   
  166.   
  167.         /// <summary>  
  168.         /// Updates employee's record  
  169.         /// </summary>  
  170.         /// <param name="employee"></param>  
  171.         private void UpdateEmployeeDetails(Employee employee)  
  172.         {  
  173.             var employeeDetails = WebAPI.PutCall(API_URIs.employees+ "?id="+employee.ID, employee);  
  174.             if (employeeDetails.Result.StatusCode == System.Net.HttpStatusCode.OK)  
  175.             {  
  176.                 ResponseMessage = employee.FirstName + "'s details has successfully been updated!";  
  177.             }  
  178.             else  
  179.             {  
  180.                 ResponseMessage = "Failed to update"+ employee.FirstName + "'s details.";  
  181.             }  
  182.         }  
  183.   
  184.         /// <summary>  
  185.         /// Deletes employee's record  
  186.         /// </summary>  
  187.         /// <param name="employee"></param>  
  188.         private void DeleteEmployeeDetails(Employee employee)  
  189.         {  
  190.             var employeeDetails = WebAPI.DeleteCall(API_URIs.employees + "?id=" + employee.ID);  
  191.             if (employeeDetails.Result.StatusCode == System.Net.HttpStatusCode.OK)  
  192.             {  
  193.                 ResponseMessage = employee.FirstName + "'s details has successfully been deleted!";  
  194.             }  
  195.             else  
  196.             {  
  197.                 ResponseMessage = "Failed to delete" + employee.FirstName + "'s details.";  
  198.             }  
  199.         }  
  200.         #endregion  
  201.     }  
  202. }  
Finally, the WPF View, which is used to display the REST API operations.       
  • Get-Button: This button fetches Employee's details
  • DataGrid will display all the records fetched, But DataGrid will only be visible after clicking on Get-Button (BooleanToVisibilityConvertor)
  • Update-Button: You can select a record from DataGrid & update the same in DataGrid as DataGrid is editable.
  • Delete-Button: You can select & delete employee records.
  • Register-Button: It responsible for the visibility of form below Update & Delete Buttons.
  • Post-Button: creates a new employee as per data filled in the form
  • 2 Messages: one will show if data is updated or deleted from DB & the below one will show if the employee's record is successfully created in DB or not.
After having all these fields updated, Our MainWindow will look like this
MainWindow.xaml
  1. <Window x:Class="A.MainWindow"    
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
  3.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    
  4.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
  6.         mc:Ignorable="d"    
  7.         xmlns:ViewModel="clr-namespace:A"    
  8.         Title="MainWindow" Height="600" Width="350">    
  9.     <Window.Resources>    
  10.         <ViewModel:MainWindowViewModel x:Key="VM" />    
  11.         <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>    
  12.     </Window.Resources>    
  13.     <Grid x:Name="MainGrid"    
  14.         DataContext="{Binding Source={StaticResource VM}}"     
  15.         HorizontalAlignment="Center">    
  16.         <Grid.RowDefinitions>    
  17.             <RowDefinition Height="Auto"/>    
  18.             <RowDefinition Height="Auto"/>    
  19.             <RowDefinition Height="4*"/>    
  20.         </Grid.RowDefinitions>    
  21.     
  22.         <StackPanel x:Name="StackPanelGetPost"    
  23.             Orientation="Horizontal"    
  24.             HorizontalAlignment="Center"    
  25.             Margin="0 10 0 0">    
  26.             <Button x:Name="ButtonGet"    
  27.                 Command="{Binding GetButtonClicked}"    
  28.                 Height="20"    
  29.                 Width="120"    
  30.                 Content="GET"/>    
  31.             <Button x:Name="ButtonPost"    
  32.                 Command="{Binding ShowRegistrationForm}"    
  33.                 Margin="10 0 0 0"    
  34.                 Height="20"    
  35.                 Width="120"    
  36.                 Content="Register Employee"     
  37.                 VerticalAlignment="Bottom"/>    
  38.         </StackPanel>    
  39.         <Grid x:Name="GridEmployeeDetails"    
  40.               Visibility="{Binding IsLoadData, Converter={StaticResource BooleanToVisibilityConverter}}"    
  41.                Grid.Row="1">    
  42.             <Grid.RowDefinitions>    
  43.                 <RowDefinition Height="Auto"/>    
  44.                 <RowDefinition Height="*"/>    
  45.                 <RowDefinition Height="*"/>    
  46.             </Grid.RowDefinitions>    
  47.             <DataGrid x:Name="DataGridEmployee"    
  48.                   ItemsSource="{Binding Employees}"    
  49.                   SelectedItem="{Binding SelectedEmployee}"    
  50.                    AutoGenerateColumns="False"    
  51.                   AlternatingRowBackground="LightBlue"     
  52.                   BorderBrush="Gray"     
  53.                   BorderThickness="5"      
  54.                   Background="LightGray"    
  55.                   Margin="0 10 0 0"    
  56.                   RowBackground="LightGray"     
  57.                   Width="310" >    
  58.                 <DataGrid.Columns>    
  59.                     <DataGridTextColumn x:Name="ColumnFirstName"    
  60.                                     Header="First Name"    
  61.                                     Binding="{Binding FirstName}"/>    
  62.                     <DataGridTextColumn x:Name="ColumnLastName"    
  63.                                     Header="Last Name"    
  64.                                     Binding="{Binding LastName}"/>    
  65.                     <DataGridTextColumn x:Name="ColumnGender"    
  66.                                     Header="Gender"    
  67.                                     Binding="{Binding Gender}"/>    
  68.                     <DataGridTextColumn x:Name="ColumnSalary"    
  69.                                     Header="Salary"    
  70.                                     Binding="{Binding Salary}"/>    
  71.                 </DataGrid.Columns>    
  72.             </DataGrid>    
  73.             <StackPanel x:Name="StackPanlePutDelete"    
  74.                         HorizontalAlignment="Center"    
  75.                         Margin="0 10 0 0"    
  76.                         Orientation="Horizontal"    
  77.                         Grid.Row="1">    
  78.                 <Button x:Name="ButtonPut"    
  79.                         Command="{Binding PutButtonClicked}"    
  80.                         CommandParameter="{Binding SelectedEmployee}"    
  81.                         Height="20"    
  82.                         Width="120"    
  83.                         Content="Update"/>    
  84.                 <Button x:Name="ButtonDelete"    
  85.                         Command="{Binding DeleteButtonClicked}"    
  86.                         CommandParameter="{Binding SelectedEmployee}"    
  87.                         Margin="10 0 0 0"    
  88.                         Height="20"    
  89.                         Width="120"    
  90.                         Content="Delete"/>    
  91.             </StackPanel>    
  92.             <TextBlock x:Name="TextBlockResponse"        
  93.                    Text="{Binding ResponseMessage}"    
  94.                    HorizontalAlignment="Center"        
  95.                    Margin="20 8 0 0"          
  96.                    Grid.Row="2" />    
  97.         </Grid>    
  98.            
  99.     
  100.         <Grid x:Name="GridCreateNewEmployee"    
  101.             Visibility="{Binding IsShowForm, Converter={StaticResource BooleanToVisibilityConverter}}"    
  102.             Grid.Row="2">    
  103.             <Grid.RowDefinitions>    
  104.                 <RowDefinition Height="Auto"/>    
  105.                 <RowDefinition Height="Auto"/>    
  106.                 <RowDefinition Height="Auto"/>    
  107.                 <RowDefinition Height="Auto"/>    
  108.                 <RowDefinition Height="Auto"/>    
  109.                 <RowDefinition Height="5*"/>    
  110.             </Grid.RowDefinitions>    
  111.             <Grid.ColumnDefinitions>    
  112.                 <ColumnDefinition Width="Auto"/>    
  113.                 <ColumnDefinition Width="Auto"/>    
  114.             </Grid.ColumnDefinitions>    
  115.             <Label x:Name="LabelUserFirstName"            
  116.                Content="First Name:"        
  117.                Margin="0 10 0 0"/>    
  118.             <Label x:Name="LabelUserLastName"             
  119.                Content="Last Name:"            
  120.                Grid.Row="1"/>    
  121.             <Label x:Name="LabelGender"             
  122.                Content="Gender:"            
  123.                Grid.Row="2"/>    
  124.             <Label x:Name="LabelSalary"             
  125.                Content="Salary:"            
  126.                Grid.Row="3"/>    
  127.     
  128.             <TextBox x:Name="TextBoxUserFirstName"          
  129.                  Text="{Binding FirstName}"        
  130.                  Height="20"            
  131.                  Width="150"           
  132.                  Grid.Column="1"/>    
  133.             <TextBox x:Name="TextBoxUserLastName"          
  134.                  Text="{Binding LastName}"        
  135.                  Height="20"            
  136.                  Width="150"           
  137.                  Grid.Row="1"    
  138.                  Grid.Column="1"/>    
  139.             <TextBox x:Name="TextBoxGender"          
  140.                  Text="{Binding Gender}"        
  141.                  Height="20"            
  142.                  Width="150"           
  143.                  Grid.Row="2"    
  144.                  Grid.Column="1"/>    
  145.             <TextBox x:Name="TextBoxSalary"     
  146.                  Text="{Binding Salary}"           
  147.                  Height="20"            
  148.                  Width="150"            
  149.                  Grid.Column="1"            
  150.                  Grid.Row="3"/>    
  151.     
  152.             <Button x:Name="ButtonAdd"            
  153.                 Height="20"            
  154.                 Width="100"            
  155.                 Content="POST"            
  156.                 HorizontalAlignment="Center"            
  157.                 Margin="20 10 0 0"          
  158.                 Command="{Binding PostButtonClick}"      
  159.                 CommandParameter="{Binding CreateEmployee}"    
  160.                 Grid.Row="4"            
  161.                 Grid.ColumnSpan="2"/>    
  162.     
  163.             <TextBlock x:Name="TextBlockMessage"     
  164.                    Text="{Binding ShowPostMessage}"    
  165.                    HorizontalAlignment="Center"        
  166.                    Margin="20 8 0 0"          
  167.                    Grid.Row="5"        
  168.                    Grid.ColumnSpan="2"/>    
  169.         </Grid>    
  170.     </Grid>    
  171. </Window>     
Now run that beautiful piece of code, you will be able to perform the actions the same as in the following gif.
 
Note
Watch the complete gif to come across all the operations.
 
 
That just looks delicious. Everything has been added in perfect amount & it is working as smooth as butter on a hot pan & believe me, the final product does taste good.
So, folks, This is how you call a REST API in your C# backed project.
 

Conclusion

  • We can have 4 very generic methods, each representing interfaces of a REST APIs. We achieved this by using generic in our code
  • How to create a basic UI in WPF for these operations
  • How to hide/unhide forms or a particular section of the screen using BooleanToVisibilityConvertor
I will leave you here to do further R & D. Find the source code here for your reference. Give it a shot!
I also appreciate the patience of the audience who has come along for all 3 parts to learn this. Kudos.
 
If you have all the 3 projects running under 1 solution, then you have to select 2 major projects as the startup project. Go to the solution properties and do as follows:
 
 
If you wish to talk, feel free to meet me @

Recommended Ebook

WPF Simplified: Build Windows Apps Using C# and XAML

Download Now!
Similar Articles