Walkthrough of Xamarin in VS2017 – Part One

    0
    35

    Introduction

    When trying to teach myself Xamarin using the Microsoft tutorial (https://docs.microsoft.com/en-au/visualstudio/cross-platform/build-apps-with-native-ui-using-xamarin-in-visual-studio) I struggled.  The walkthrough is very simple and a number of the options and libraries have changed.  I therefore decided to create this mini-series to expand on the original how-to.

    A lot of articles giving instruction  are very basic. I wanted to start with the basics of Xamarin, update them for today (June 2017) and then start to extend the functionality so that its not just a how to, but how to code a decent app – not just an example code snipts.

    Setup, Install and Emulator Tips

    I’m currently using Visual Studio 2017 Community edition.

    For instructions see https://docs.microsoft.com/en-au/visualstudio/cross-platform/setup-and-install

    I should also mention I suffered from this strange bug, where you cannot boot Windows after installing VS2017 & Xamarin.  So ensure you backup your machine first, just in case:

    https://connect.microsoft.com/VisualStudio/feedback/details/1608843/after-installation-of-vs2015-windows-10-will-not-boot

    You need to get a free API key from http://openweathermap.org/appid

    I have a Windows Phone Lumia 1520 for testing the UWP version and I am using the Android Emulators (you can access these in Visual Studio Tools, Android, Android Emulation Manager menu. 

    I did have some issues with the Android emulators until I simplified the configurations (ARM Phone, ARM Tablet, x86 Phone & x86 Table) to all be running 7.1.1, API level 25.

    I am not an Android expert, so I’m sure there will be many comments to suggest a better solution than this. 

    In this editor you can also Start an emulator.  Again, I had issues with emulators (maybe as my machine only has 4Gb of memory), however everything worked file as long as I:

    1. Started the emulator manually and left it running (rather than letting VS try to start it up);
    2. Build then Deploy to the emulator manually;
    3. Debug / Run the application through VS.

    I’ve not yet tried iOS.  When I have the opportunity, I will install the Xamarin Live Player on an iPhone and update this article…

    Final point, with VS & Xamarin the XAML doesn’t currently show a ‘screen’ like a general UWP / WPF applications.  However you can see what you app will look like when designing, by opening the View, Other Windows,  Xamarin Forms Previewer.

    Create your Project

    File, New Project.  Under Visual C# template section you should find (and select) Cross-Platorm.  On the right select Cross Platform App (Xamarin), then enter the name WeatherApp and click Ok.

    On the next screen select Blank App, Xamarin.Forms and Portable Class Library (PCL).

    Visual Studio will now create your Solution, asking you which version of Windows to Target.  I selected Windows 10 Novemember Update (10.0; Build 10586) as the Minimum and Windows 10 Creators Update (10.0; Build 15063) as my Target version.

    Visual Studio will ask you to enter the details of you MAC for iOS development…  You can ignore this step untill you want to compile/deploy/debug for iOS. 

    The created Solution will include four projects:

    • WeatherApp
    • WeatherApp.Android
    • WeatherApp.iOS
    • WeatherApp.UWP (Universal Windows)

    Note: the first project historically was called ‘WeatherApp (Portable)’.

    A bit more house keeping…

    In the Solution Explorer right click on the WeatherApp.Android project and go to Properties:

    1. On the Andriod Options tab, un-check “Use Fast Deployment (debug mode only).
    2. On the Application tab, ensure the Compile using Android version is set to 7.1 so that it matches the emulator setup above.
    3. Save and close the Properties.

    In the Solution Explorer, right click on the Solution ‘WeatherApp’ (4 projects) and select Manage NuGet packages for Solution.

    In the Search box on the Browse tab, enter Newton.Json then on the right check Project and click on the Install button.

    You may get some popups asking you to Review Changes and Licence Acceptance.  Click Ok / I Accept…

    In the Search enter Microsoft.Net.Http then click on the Install button. You may get some popups asking you to Review Changes and Licence Acceptance.  Click Ok / I Accept…

    At time of writing the template has a number of out-of-date NuGet packages, which should be updated.

    Go to the Consolidate tab (if there is an update waiting to be applied).  Clear out the search box so that the package is displayed, select the package and click Install.

    Go to the Update tab (even if there is no number there indicating that the are waiting updates).  Check Select all Packages and click on Update.  Again, you may get some popups asking you to Review Changes and Licence Acceptance.  Click Ok / I Accept…

    At this point I get a message saying that Visual Studio needs to restart.  Click Restart and when the VS has restarted and the Solution reloaded, in the Solution Explorer, right click on the Solution ‘WeatherApp’ (4 projects) and select Manage NuGet packages for Solution.   Go to the Update tab select any packages that need updating and complete the update process.

    At this stage, I would you suggest you Build the Solution, start your emulator or connect your device and Deploy the project and then run through the debugger.   My example here is using the Android Project (set as Startup) to the Emulator – but it doesn’t matter which project you choose to use (UWP, Android or iOS). 

    Note that the emulator selected next to my Play button in VS matches the emulator I started earlier and deployed to.

    To run (for example) on my Windows Phone, select ARM as the CPU, WeatherApp.UWP as the project and then RUN (Device).

    I would suggest leaving the emulator running (if you are using one), just hit Stop in Visual Studio.

    Finally we are ready to do some coding…

    The Code

    What will this App actually do?  Simply, for a given Zip code the application will show a number of weather attributes that are returned from the Open Weather Map website.

    First we need a class to contain the return information.  Right click on the WeatherApp project, then select Add, then Class (usually right down the very bottom).  Name the class Weather.cs and click on Add.

    Replace the template code with the following:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace WeatherApp
    {
 public class Weather
 {
 public string Title { get; set; }
 public string Temperature { get; set; }
 public string Wind { get; set; }
 public string Humidity { get; set; }
 public string Visibility { get; set; }
 public string Sunrise { get; set; }
 public string Sunset { get; set; }
    
 public Weather()
 {
 
 
 this.Title = " ";
 this.Temperature = " ";
 this.Wind = " ";
 this.Humidity = " ";
 this.Visibility = " ";
 this.Sunrise = " ";
 this.Sunset = " ";
 }
 }
    }

    => This is a simple class that will hold the data returned from the Open Weather Map website.  The constructor sets all variables to be blank strings by default.

    Next we need a class to pass our request to the Open Weather Map website and return the response for our application to use.

    Right click on the WeatherApp project, then select Add, then Class.  Name the class DataService.cs and click on Add.

    using Newtonsoft.Json;
    using System.Threading.Tasks;
    using System.Net.Http;
    
    namespace WeatherApp
    {
 public class DataService
 {
 public static async Task<dynamic> getDataFromService(string pQueryString)
 {
 HttpClient client = new HttpClient();
 var response = await client.GetAsync(pQueryString);
    
 dynamic data = null;
 if (response != null)
 {
 string json = response.Content.ReadAsStringAsync().Result;
 data = JsonConvert.DeserializeObject(json);
 }
    
 return data;
 }
 }
    }

    => This is a simple class that is passed the parameter string to send to the Open Weather Map website , creates a HTTP client to send that information, then awaits a response. 

    The parameter string sent to the HTTP client is simply the a call to the website with our Zip Code, AppId and Units as parameters:

    When the response is receive from the website, the Json library converts the string into a basic key/value list object we can easily “query” to put our results into variables.  If you look at this example returned string:

    {“coord”:{“lon”:-103.14,”lat”:39.69},”weather”:[{“id”:800,”main”:”Clear”,”description”:”clear sky”,”icon”:”01n”}],”base”:”stations”,”main”:{“temp”:58.96,”pressure”:1016,”humidity”:39,”temp_min”:48.2,”temp_max”:64.4},”visibility”:16093,”wind”:{“speed”:6.93,”deg”:140},”clouds”:{“all”:1},”dt”:1497596100,”sys”:{“type”:1,”id”:533,”message”:0.0076,”country”:”US”,”sunrise”:1497612254,”sunset”:1497666163},”id”:0,”name”:”Anton”,”cod”:200}

    If you look at this string data that is returned, you can make out the responses from the website, for example the Temp is 58.96.  The next code block shows how we query the Json result object to populate our internal data structure.

    —–

    We need a class to call our DataService and populate our internal Weather class.

    Right click on the WeatherApp project, then select Add, then Class.  Name the class Core.cs and click on Add.

    using System; 
    using System.Threading.Tasks; 
    using WeatherApp;
    
    namespace WeatherApp 
    { 
 public class Core 
 { 
 public static async Task<Weather> GetWeather(string pZipCode) 
 { 
 
 string key = "YOUR KEY HERE"; 
 string queryString = "http://api.openweathermap.org/data/2.5/weather?zip=" 
 + pZipCode + ",us&appid=" + key + "&units=imperial"; 
    
 
 if (key != "YOUR API KEY HERE")
 {
 throw new ArgumentException("You must obtain an API key from openweathermap.org/appid and save it in the 'key' variable.");
 }
    
 dynamic results = await DataService.getDataFromService(queryString).ConfigureAwait(false); 
    
 if (results["weather"] != null) 
 { 
 Weather weather = new Weather(); 
 weather.Title = (string)results["name"]; 
 weather.Temperature = (string)results["main"]["temp"] + " F"; 
 weather.Wind = (string)results["wind"]["speed"] + " mph"; 
 weather.Humidity = (string)results["main"]["humidity"] + " %"; 
 weather.Visibility = (string)results["weather"][0]["main"]; 
    
 DateTime time = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); 
 DateTime sunrise = time.AddSeconds((double)results["sys"]["sunrise"]); 
 DateTime sunset = time.AddSeconds((double)results["sys"]["sunset"]); 
 weather.Sunrise = sunrise.ToString() + " UTC"; 
 weather.Sunset = sunset.ToString() + " UTC"; 
 return weather; 
 } 
 else 
 { 
 return null; 
 } 
 } 
 } 
    }

    => In this code block, we first create the parameter string (see above) that is sent to the getDataFromService function. 

    With the response returned from the website, we parse the key/value list to put the values into our internal Weather class.

    When you signed up to the Open Weather Map website you will have been sent an email which will include your API key.  Copy that key into the two places about marked “YOUR API KEY HERE”. Note: you do need to include the &APPID= part of the key.

    ——

    Open the WeatherApp MainPage.xaml and replace the XAML with:

    ="1.0"="utf-8"
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:WeatherApp"
                 x:Class="WeatherApp.MainPage">
    
 <StackLayout>
 <StackLayout Margin="10,0,0,0" VerticalOptions="Start" HorizontalOptions="Start" WidthRequest="400" BackgroundColor="#545454">
 <Label Text="Weather App" x:Name="lblTitle"/>
    
 <StackLayout HorizontalOptions="Start" Margin="10,10,0,0" VerticalOptions="Start"  WidthRequest="400">
 <Label Text="Search by Zip Code" FontAttributes="Bold" TextColor="White" Margin="10" x:Name="lblSearchCriteria" VerticalOptions="Start"/>
 <Label Text="Zip Code" TextColor="White" Margin="10" x:Name="lblZipCode"/>
 <StackLayout  Orientation="Horizontal" VerticalOptions="Start">
 <Entry WidthRequest="100" x:Name="edtZipCode"  VerticalOptions="Start"/>
 <Button Text="Get Weather" x:Name="btnGetWeather"  VerticalOptions="Start"/>
 </StackLayout>
 </StackLayout>
 </StackLayout>
 
 <StackLayout VerticalOptions="StartAndExpand">
 <Label Text ="Location" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtLocation"/>
 <Label Text ="Temperature" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtTemperature"/>
 <Label Text ="Wind Speed" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtWind"/>
 <Label Text ="Humidity" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtHumidity"/>
 <Label Text ="Visibility" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtVisibility"/>
 <Label Text ="Sunrise" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtSunrise"/>
 <Label Text ="Sunset" TextColor="#FFA8A8A8" FontSize="14"/>
 <Label Text ="" Margin="10,0,0,10" x:Name="txtSunset"/>
 </StackLayout>
 </StackLayout>
    </ContentPage>

    Save All at this point.

    => This XAML is very basic a heading section that allows you to enter a Zip Code with the button to kick off the process.  Then a detail section that displays the results.

    —-

    Now open the MainPage.xaml.cs, in the MainPage() constructor add the following code to link a procedure to the button being pushed:

    public MainPage()
    {
 InitializeComponent();
    
 btnGetWeather.Clicked += btnGetWeather_Click;
    }

    Then add the button push code:

    private async void btnGetWeather_Click(object sender, EventArgs e)
    {
 if (!String.IsNullOrEmpty(edtZipCode.Text))
 {
 Weather weather = await Core.GetWeather(edtZipCode.Text);
 
 if (weather != null)
 {
 txtLocation.Text = weather.Title;
 txtTemperature.Text = weather.Temperature;
 txtWind.Text = weather.Wind;
 txtVisibility.Text = weather.Visibility;
 txtHumidity.Text = weather.Humidity;
 txtSunrise.Text = weather.Sunrise;
 txtSunset.Text = weather.Sunset;
    
 btnGetWeather.Text = "Search Again";
 }
 }
    } 

    => Button pressed code calls the function to populate the weather variable with the data returned from the webstite and then updates each of the on screen controls with the results.

    —-

    If you now Build and Deploy this project, you will now get a working app that displays weather data!  Not living in the US, I used Zip Code 80801 for testing.

    And there you have it, an App that will deploy to Windows UWP, Android Mobile and iOS – with a single code stream!

    It is at this stage, generally a walk-throughs stops, however I would argue this is not an App, only a code sample.

    Soon I will publish the next article and keep building this into a proper App:

    https://www.codeproject.com/Articles/1192180/Walkthrough-for-Xamarin-in-VS2017-Part-Two

    LEAVE A REPLY