Xamarin.Forms – Ejecutando código JavaScript desde C#

Si has trabajado anteriormente con Xamarin, tal vez hayas utilizado el control WebView. Dicho control nos sirve para mostrar una página web dentro de nuestra aplicación, tal como el siguiente ejemplo:

Tal vez, una cosa que desconozcas es que se puede invocar una función JavaScript, ¡Desde tu código C#!

Para esto, lo que haremos será crear un archivo tipo .html dentro de nuestro proyecto portable, en una solución tipo Xamarin.Forms:

Dicho archivo, debe tener en sus propiedades, asignada la opción «Embedded Resource» en Build Action:

Dicho archivo, contiene la siguiente estructura a modo de ejemplo:

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Cálculo de Factoriales</title>    
</head>
<body>
    http://code.jquery.com/jquery-2.1.4.min.js
    <h1>Cálculo de Factoriales</h1>
    <div id='result'/>
    
        function printFactorial(number)
        {            
            var result = 1;
            var factorialNumber = parseInt(number);
            $('#result').empty();
            
            for (var i = 1; i ');
        }
    
</body>
</html>

Procederemos también, a crear la definición de nuestro archivo .xaml, el cual contendrá una caja de texto, un botón para invocar el método Javascript, y un WebView donde desplegaremos la información deseada:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:JavaScriptAndCSharp"
             x:Class="JavaScriptAndCSharp.MainPage">

    <StackLayout>
        <Label Text="Factorial" FontSize="Medium" HorizontalOptions="Center" />
        <StackLayout Orientation="Horizontal" HorizontalOptions="Center">
            <Label Text="Factorial Number: " VerticalOptions="Center" />
            <Entry x:Name="txtNumber" Text="5" WidthRequest="40" />
        </StackLayout>
        <Button x:Name="btnCallJS" Text="Call JavaScript" Clicked="OnbtnCallJSClicked"/>
        <WebView x:Name="webView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
    </StackLayout>

</ContentPage>

Ahora viene la parte interesante, en primer lugar, debemos de cargar la página HTML que deseemos, en nuestro caso, la página se llama test.html, por lo que crearemos una función dentro de nuestro archivo MainPage.xaml.cs, que lleve a cabo dicha carga, de la siguiente manera:

        HtmlWebViewSource LoadHTMLFileFromResource()
        {
            var source = new HtmlWebViewSource();

            // Carga el archivo HTML embebido como un recurso en el PCL
            var assembly = typeof(MainPage).GetTypeInfo().Assembly;
            var stream = assembly.GetManifestResourceStream("JavaScriptAndCSharp.test.html");
            using (var reader = new StreamReader(stream))
            {
                source.Html = reader.ReadToEnd();
            }
            return source;
        }

El código anterior, lo que hace es obtener el archivo HTML, y regresarlo como un órigen html para nuestro control WebView, debemos asignar dicha lectura en el constructor de nuestra página:

        public MainPage()
        {
            InitializeComponent();
            webView.Source = LoadHTMLFileFromResource();
        }

Por último, codificaremos el manejador de eventos del botón definido en nuestro código XAML, llamado «btnCallJS, de la siguiente forma:

        private void OnbtnCallJSClicked(object sender, EventArgs e)
        {        
            if (string.IsNullOrWhiteSpace(txtNumber.Text))
            {
                return;
            }
            int number = int.Parse(txtNumber.Text);
            webView.Eval(string.Format("printFactorial({0})", number));
        }

La forma de invocar las funciones dentro del archivo html, es a través de la función «Eval», a la cual se le deben de pasar los parámetros obtenidos a través de la interfaz de usuario.

Con esto, tendrás una aplicación funcional que es capaz de invocar código Javascript:

Saludos.

Xamarin Forms: Consumiendo un servicio web basado en JSON Parte 3: Creando Creando la Vista

Para finalizar este proyecto, crearemos el formulario de la interfaz gráfica, y haremos los ajustes finales para tener nuestra aplicación corriendo.

En primer lugar, crearemos la última carpeta que nos hace falta llamada View:

image

En la nueva carpeta crearé un nuevo elemento del tipo Forms Xaml Page al cual llamaremos MainPage:

image

En el formulario creado, usaremos el siguiente código para el archivo MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="JsonWebServices.View.MainPage">
  <ContentPage.Content>
    <StackLayout Padding="30">
      <StackLayout Orientation="Horizontal">
        <Label Text="Latitude" WidthRequest="130"></Label>
        <Entry x:Name="txtLatitude" WidthRequest="150"></Entry>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Longitude" WidthRequest="130"></Label>
        <Entry x:Name="txtLongitude" WidthRequest="150"></Entry>
      </StackLayout>
      <Button x:Name="btnSearch" Clicked="OnClicked"
              WidthRequest="75" Text="Search" TextColor="White"
              BackgroundColor="Blue"></Button>
      <StackLayout Orientation="Horizontal">
        <Label Text="Location: " TextColor="Green"
               WidthRequest="130"></Label>
        <Label Text="{Binding StationName}"></Label>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Elevation: " TextColor="Green"
               WidthRequest="130"></Label>
        <Label Text="{Binding Elevation}"></Label>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Temperature: " TextColor="Green"
               WidthRequest="130"></Label>
        <Label Text="{Binding Temperature}"></Label>
      </StackLayout>
      <StackLayout Orientation="Horizontal">
        <Label Text="Humidity: " TextColor="Green"
               WidthRequest="130"></Label>
        <Label Text="{Binding Humidity}"></Label>
      </StackLayout>
    </StackLayout>
  </ContentPage.Content>
</ContentPage>

Por otra parte, en el archivo MainPage.xaml.cs, debemos definir una variable que será la instancia del ViewModel de la siguiente manera:

public MainPageViewModel vm;

Esta variable la inicializaremos dentro del constructor:

vm = new MainPageViewModel();

De igual forma, dentro del constructor debemos asignar el contexto de datos a dicha variable de la siguiente forma:

BindingContext = vm;

Por último, crearemos el manejador de eventos que hará la llamada al servicio web, en primer lugar, obtendremos la información de las cajas de texto, paso seguido definiremos la url del servicio web, y al último haremos la llamada a través del método especificado:

        public async void OnClicked(object sender, EventArgs e)
        {
            var longitude = double.Parse(txtLongitude.Text);
            var latitude = double.Parse(txtLatitude.Text);
            
            var url = string.Format(@"http://api.geonames.org/findNearByWeatherJSON?formatted=true&lat={0}&lng={1}&username=demo&style=full", latitude, longitude);
            await vm.GetWeatherAsync(url);
        }

quedando de la siguiente manera el archivo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JsonWebServices.ViewModel;
using Xamarin.Forms;

namespace JsonWebServices.View
{    
    public partial class MainPage : ContentPage
    {
        public MainPageViewModel vm;
        public MainPage()
        {
            vm = new MainPageViewModel();
            BindingContext = vm;
            InitializeComponent();
        }
        public async void OnClicked(object sender, EventArgs e)
        {
            var longitude = double.Parse(txtLongitude.Text);
            var latitude = double.Parse(txtLatitude.Text);
            
            var url = string.Format(@"http://api.geonames.org/findNearByWeatherJSON?formatted=true&lat={0}&lng={1}&username=demo&style=full", latitude, longitude);
            await vm.GetWeatherAsync(url);
        }
    }
}

Por último, modificaremos el constructor de la clase App para que asigne a la página MainPage como la página principal:

        public App()
        {
            // The root page of your application
            MainPage = new MainPage();
        }

Una vez terminada la codificación, podemos buscar coordenadas en cualquier aplicación de mapas para probar:

image

Ejecutaremos la aplicación e Insertaremos estas coordenadas, al presionar el botón search, nos mostrará el resultado correspondiente:

image

Definitivamente hay cosas que pueden ser mejoradas, pero queda como tarea para la casa, Espero que esta serie les haya gustado y servido. Recuerden que todo el proyecto lo pueden descargar desde aquí.

Saludos.

Xamarin Forms: Pre visualizando los formularios (Opción 2: Gorilla Player)

La segunda opción para llevar a cabo la pre visualización de los formularios, es a través de Gorilla Player. Aún se encuentra en estado beta, y para utilizarlo se requiere de una invitación, ya que es una beta privada, a mí me tardó alrededor de una semana en llegar el código desde que la solicité. Una vez que nos ha llegado el código, podemos realizar la descarga desde aquí. Procederemos a instalarlo, e inmediatamente nos aparecerá una ventana para loguearnos al servicio:

Screen Shot 05-03-16 at 11.25 AM

Posterior a este paso, nos aparecerá una venta con los 3 pasos que debemos llevar a cabo para utilizar el servicio:

1.- Verificar que Gorilla Player se encuentre corriendo desde la barra de tareas:

Screen Shot 05-04-16 at 08.40 AM

2.- Se requiere desplegar la aplicación derivada de la solución Player.sln, a cada uno de los emuladores y dispositivos donde vayamos a llevar a cabo pruebas:

2a) Abrir la solución desde el Wizard de Gorilla Player:

Screen Shot 05-04-16 at 08.43 AM

Screen Shot 05-04-16 at 08.44 AM

2b) Desplegar el dispositivo en el emulador o dispositivo físico correspondiente(Debemos asegurarnos de descargar los paquetes de nuget faltantes:

Screen Shot 05-04-16 at 09.15 AM

3c) La aplicación tratará de encontrar el servidor de Gorilla Player en el equipo que tengamos conectado. Una vez realizado este paso, nos indicará que se encuentra listo para realizar las pre visualizaciones necesarias:

Screenshot_2016-05-04-09-22-11

3.- Probar los ejemplos que vienen en la solución:

3a) Abrir la solución de ejemplo:

Screen Shot 05-04-16 at 09.30 AM

3b) De nueva cuenta, restaurar los paquetes de nuget:

Screen Shot 05-04-16 at 09.30 AM 001

3c) Un ícono de un gorila nos mostrará que estamos conectados y listos para probar el código XAML de nuestro proyecto:

Screen Shot 05-04-16 at 09.34 AM

3d) Ahora, basta con que abramos la aplicación recién instalada llamada Gorilla Player desde nuestro emulador o dispositivo, y ejecutar el comando Guardar desde el formulario que queremos probar desde Visual Studio (Ctrl + S) para que nos despliegue el resultado en el dispositivo o emulador deseado:

Screenshot_2016-05-04-09-35-43

Al llevar a cabo algún cambio, bastará con volver a presionar Ctrl + S para verificar el cambio en tiempo real:

Screenshot_2016-05-04-09-37-49

Podemos ahora abrir algún proyecto desarrollado previamente, y ver en tiempo real si existe algún problema de diseño como en el siguiente caso:

Screenshot_2016-05-04-10-12-00

Este formulario, lo podemos corregir de una manera muy sencilla y rápida con ayuda de Gorilla Player:

Screenshot_2016-05-04-10-15-46

Como podemos ver, llevar a cabo la realización de formularios a través de Gorilla Player es una excelente alternativa para ahorrarnos muchísimo tiempo. La única advertencia que hay que tener en cuenta, es que el servicio, seguramente tendrá un costo extra en la versión final.

Por último, como advertencia, Visual Studio en conjunto con Gorilla Player se me congela si el proyecto se encuentra alojado en un repositorio GitHub.

Saludos.

Xamarin Forms: Pre visualizando los formularios (Opción 1)

Una de las características más solicitadas por los desarrolladores en Xamarin Forms, es el poder ver en tiempo de diseño sus formularios. Aunque en el evento “Xamarin Evolve 2016” se ha anunciado un pre visualizador oficial, aún se encuentra en estado Alpha.

Una de las opciones para llevar a cabo una previsualización de nuestros formularios (aunque no es en tiempo real), es la utilización del proyecto Windows Phone Forms to Xamarin Forms, el cual nos permite convertir un formulario desarrollado para Windows Phone en un formulario de Xamarin. Aquí van las instrucciones:

1.- Creando el formulario en un proyecto tipo Windows Phone

Debemos crear un nuevo formulario en un proyecto tipo Windows Phone, o bien utilizar uno existente:

Screen Shot 04-28-16 at 10.25 AM

Screen Shot 04-28-16 at 10.25 AM 001

Screen Shot 04-28-16 at 10.27 AM

Una vez agregado el archivo en el proyecto, podemos comenzar a diseñarlo con ayuda del diseñador integrado para este tipo de proyectos, en mi caso, crearé un formulario que quedará de la siguiente manera:

Screen Shot 04-28-16 at 10.28 AM

con el código correspondiente:

<phone:PhoneApplicationPage
    x:Class="JsonWebServices.WinPhone.WeatherPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="XAMARIN" FontSize="20"/>
            <TextBlock Text="Weather App" Margin="9,-7,0,0" FontSize="72" />
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal">
                    <TextBlock>Latitud</TextBlock>
                    <TextBox Width="300" x:Name="txtLatitude"></TextBox>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock>Longitud</TextBlock>
                    <TextBox Width="300" x:Name="txtLongitude"></TextBox>
                </StackPanel>
                <Button Content="Obtener Datos" Click="ButtonBase_OnClick"></Button>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="130">Ubicación</TextBlock>
                    <TextBlock Text="{Binding StationName}"></TextBlock>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="130">Elevación</TextBlock>
                    <TextBlock Text="{Binding Elevation}"></TextBlock>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="130">Temperatura</TextBlock>
                    <TextBlock Text="{Binding Temperature}"></TextBlock>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Width="130">Humedad</TextBlock>
                    <TextBlock Text="{Binding Humidity}"></TextBlock>
                </StackPanel>
            </StackPanel>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

2.- Leer la documentación y descargar la herramienta

El autor de la herramienta es Jonathan Yates, y podemos encontrar la entrada principal de la herramienta aquí. Aunque los enlaces de la página a la página de OneDrive llevan a un link desactualizado, puedes enviarle un mail a pete@petevickers.co.uk para solicitarle una copia de la herramienta, quien, en mi caso particular me respondió mi correo de forma rápida.

3.- Utilizando la herramienta

Una vez que hemos instalado la herramienta, nos aparecerá algo parecido a esto:

Screen Shot 04-28-16 at 10.37 AM

Lo que haremos en este caso en particular, será colocarle un espacio de nombres dentro del proyecto donde se alojará el formulario, seleccionaremos la ruta al archivo, y automáticamente nos generará una ruta para un archivo destino:

Screen Shot 04-28-16 at 10.40 AM

Posteriormente, debemos dar click en el botón “Generate”, lo cual nos mostrará un mensaje si la conversión es correcta:

Screen Shot 04-28-16 at 10.40 AM 001

El resultado será el siguiente código, que podremos reutilizar para no iniciar nuestros desarrollos desde cero:

<?xml version="1.0" encoding="utf-8" ?>
<!--Code generated by 'WP to XF' created by GUI Innovations Limited-->
<!--For more details, enhancement requests, bugs etc.  please email-->
<!--             pete@gui-innovations.com  - Thanks                -->
<formtype xmlns=|http://xamarin.com/schemas/2014/forms|
             xmlns:x=|http://schemas.microsoft.com/winfx/2009/xaml|
             x:Class=|PageName|>

<StackLayout Orientation="Vertical"
      VerticalOptions="FillAndExpand"
      HorizontalOptions="FillAndExpand"
      Padding="10,40,10,30"
      Spacing="10">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" BackgroundColor="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackLayout Grid.Row="0" Padding="12,17,0,28">
            <Label Text="XAMARIN" FontSize="20"/>
            <Label Text="Weather App"  FontSize="72" />
        </StackLayout>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Padding="12,0,12,0">
            <StackLayout Orientation="Vertical">
                <StackLayout Orientation="Horizontal">
                    <Label>Latitud</Label>
                    <Entry WidthRequest="300" x:Name="txtLatitude"></Entry>
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                    <Label>Longitud</Label>
                    <Entry WidthRequest="300" x:Name="txtLongitude"></Entry>
                </StackLayout>
                <Button Text="Obtener Datos"></Button>
                <StackLayout Orientation="Horizontal">
                    <Label WidthRequest="130">Ubicación</Label>
                    <Label Text="{Binding StationName}"></Label>
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                    <Label WidthRequest="130">Elevación</Label>
                    <Label Text="{Binding Elevation}"></Label>
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                    <Label WidthRequest="130">Temperatura</Label>
                    <Label Text="{Binding Temperature}"></Label>
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                    <Label WidthRequest="130">Humedad</Label>
                    <Label Text="{Binding Humidity}"></Label>
                </StackLayout>
            </StackLayout>
        </Grid>
    </Grid>
</StackLayout>
</ContentPage>

Cabe destacar que la herramienta es una muy buena ayuda para no iniciar desde cero nuestros formularios, o bien, si queremos reutilizar formularios existentes.

Saludos.

Xamarin Forms: Consumiendo un servicio web basado en JSON Parte 2: Creando el ViewModel

En este post nos enfocaremos a crear el ViewModel del proyecto. En primer lugar, crearemos una carpeta llamada ViewModel, donde alojaremos nuestro código correspondiente al ViewModel.

Crearemos una clase llamda MainPageViewModel, a la cual implementaremos la interfaz: INotifyPropertyChanged, de la siguiente manera:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using JsonWebServices.Annotations;

namespace JsonWebServices.ViewModel
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        #region InotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

Para poder llevar a cabo la notificación de un cambio en una de las propiedades para poder comunicársela a la interfaz gráfica a través de un binding, debemos crear una propiedad  por cada valor que queramos notificar a la interfaz gráfica, seguido de la llamada al método OnPropertyChanged(), como en el siguiente ejemplo:

        private string _stationName;
        public string StationName
        {
            get
            {
                return _stationName;
            }

            set
            {
                _stationName = value;
                OnPropertyChanged();
            }
        }

Para ejemplos demostrativos, implementaremos las propiedades de StationName, Elevation, Temperature y Humidity, de la siguiente forma

        #region Properties
        private string _stationName;
        private int _elevation;
        private string _temperature;
        private int _humidity;
        public string StationName
        {
            get
            {
                return _stationName;
            }

            set
            {
                _stationName = value;
                OnPropertyChanged();
            }
        }
        public int Elevation
        {
            get
            {
                return _elevation;
            }

            set
            {
                _elevation = value;
                OnPropertyChanged();
            }
        }

        public string Temperature
        {
            get
            {
                return _temperature;
            }

            set
            {
                _temperature = value;
                OnPropertyChanged();
            }
        }

        public int Humidity
        {
            get
            {
                return _humidity;
            }

            set
            {
                _humidity = value;
                OnPropertyChanged();
            }
        }
        #endregion

Para la siguiente parte, debemos instalar un par de paquetes de nuget, los cuales puedes instalar a través de la Consola de paquetes de nuget, apuntando al proyecto Portable:

Screen Shot 04-25-16 at 09.46 AM

los cuales son:

Install-Package Microsoft.Net.Http

Install-Package Newtonsoft.Json

 

Posteriormente, debemos crear un método llamado GetWeatherAsync que se encargue de llevar a cabo la solicitud al sitio web, a través de una instancia de HttpClient. y su posterior deserialización de la siguiente forma:

        public async Task GetWeatherAsync(string url)
        {
            //Creamos una instancia de HttpClient
            var client = new HttpClient();
            //Asignamos la URL
            client.BaseAddress = new Uri(url);
            //Llamada asíncrona al sitio
            var response = await client.GetAsync(client.BaseAddress);
            //Nos aseguramos de recibir una respuesta satisfactoria
            response.EnsureSuccessStatusCode();
            //Convertimos la respuesta a una variable string
            var jsonResult = response.Content.ReadAsStringAsync().Result;
            //Se deserializa la cadena y se convierte en una instancia de WeatherResult
            var weather = JsonConvert.DeserializeObject<WeatherResult>(jsonResult);
            //Asignamos el nuevo valor de las propiedades
            SetValue(weather);
        }

Por último, agregaremos un método llamado SetValue, que nos servirá para actualizar las propiedades de la clase contenida en el ViewModel, de la siguiente forma:

        private void SetValue(WeatherResult weather)
        {
            var stationName = weather.WeatherObservation.StationName;
            var elevation = weather.WeatherObservation.Elevation;
            var temperature = weather.WeatherObservation.Temperature;
            var humidity = weather.WeatherObservation.Humidity;

            StationName = stationName;
            Elevation = elevation;
            Temperature = temperature;
            Humidity = humidity;
        }

El resultado final de la clase, deberá verse de la siguiente forma:

using System;
using System.ComponentModel;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using JsonWebServices.Annotations;
using JsonWebServices.Model;
using Newtonsoft.Json;

namespace JsonWebServices.ViewModel
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        #region Properties
        private string _stationName;
        private int _elevation;
        private string _temperature;
        private int _humidity;
        public string StationName
        {
            get
            {
                return _stationName;
            }

            set
            {
                _stationName = value;
                OnPropertyChanged();
            }
        }
        public int Elevation
        {
            get
            {
                return _elevation;
            }

            set
            {
                _elevation = value;
                OnPropertyChanged();
            }
        }

        public string Temperature
        {
            get
            {
                return _temperature;
            }

            set
            {
                _temperature = value;
                OnPropertyChanged();
            }
        }

        public int Humidity
        {
            get
            {
                return _humidity;
            }

            set
            {
                _humidity = value;
                OnPropertyChanged();
            }
        }
        #endregion

        #region Methods
        public async Task GetWeatherAsync(string url)
        {
            //Creamos una instancia de HttpClient
            var client = new HttpClient();
            //Asignamos la URL
            client.BaseAddress = new Uri(url);
            //Llamada asíncrona al sitio
            var response = await client.GetAsync(client.BaseAddress);
            //Nos aseguramos de recibir una respuesta satisfactoria
            response.EnsureSuccessStatusCode();
            //Convertimos la respuesta a una variable string
            var jsonResult = response.Content.ReadAsStringAsync().Result;
            //Se deserializa la cadena y se convierte en una instancia de WeatherResult
            var weather = JsonConvert.DeserializeObject<WeatherResult>(jsonResult);
            //Asignamos el nuevo valor de las propiedades
            SetValue(weather);
        }

        private void SetValue(WeatherResult weather)
        {
            var stationName = weather.WeatherObservation.StationName;
            var elevation = weather.WeatherObservation.Elevation;
            var temperature = weather.WeatherObservation.Temperature;
            var humidity = weather.WeatherObservation.Humidity;

            StationName = stationName;
            Elevation = elevation;
            Temperature = temperature;
            Humidity = humidity;
        }
        #endregion

        #region InotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

En la siguiente entrada, nos encargaremos de la parte de la vista. Cualquier duda o comentario, no dudes en escribirlo, y recuerda que el código fuente del ejemplo lo puedes encontrar aquí.

Saludos.

Xamarin Forms: Consumiendo un servicio web basado en JSON Parte 1: Creando el Modelo

Para llevar a cabo el consumo de un servicio web basado en Json, en primer lugar, debemos tener disponible el servicio mismo. Para llevar a cabo esta demostración, utilizaré los servicios alojados en este enlace.

Esta página nos permite utilizar más de 30 servicios web diferentes, cuya respuesta puede ser XML, JSON, RDF, CSV, TXT, RSS ó KML, basta con dar click sobre el enlace requerido para que se nos muestre un ejemplo de la respuesta del servicio. Yo utilizaré el servicio findNearByWeather.

Screen Shot 04-20-16 at 09.52 AM

Screen Shot 04-20-16 at 09.53 AM

Para iniciar el desarrollo de la aplicación, debemos crear un proyecto de tipo Xamarin.Forms, de tipo Portable:

Screen Shot 04-20-16 at 10.14 AM

Una vez creado el proyecto, crearemos 1 carpeta llamada Model, y dentro de esta, crearemos una clase que aloje las propiedades que correspondan al modelo del archivo Json, a la cual llamaremos WeatherObservation.

Ahora bien, para llevar a cabo la creación de las propiedades dentro de la clase, podríamos pensar que debemos de escribirlas a mano una por una, sin embargo, Visual Studio nos ofrece la posibilidad de generar el modelo a partir del archivo json. Una vez copiado el archivo json, debemos pegarlo a través del menú Edit –> Paste Special –> Paste JSON As Classes, lo cual nos generará el siguiente código:

namespace JsonWebServices.Model
{

    public class Rootobject
    {
        public Weatherobservation weatherObservation { get; set; }
    }

    public class Weatherobservation
    {
        public int elevation { get; set; }
        public float lng { get; set; }
        public string observation { get; set; }
        public string ICAO { get; set; }
        public string clouds { get; set; }
        public string dewPoint { get; set; }
        public string cloudsCode { get; set; }
        public string datetime { get; set; }
        public string countryCode { get; set; }
        public string temperature { get; set; }
        public int humidity { get; set; }
        public string stationName { get; set; }
        public string weatherCondition { get; set; }
        public int windDirection { get; set; }
        public int hectoPascAltimeter { get; set; }
        public string windSpeed { get; set; }
        public float lat { get; set; }
    }

}

A continuación, renombraremos la clase Rootobject por WeatherResult. y modificaremos las propiedades para que inicien con mayúsculas, quedando nuestro modelo de la siguiente forma:

namespace JsonWebServices.Model
{

    public class WeatherResult
    {
        public Weatherobservation WeatherObservation { get; set; }
    }

    public class Weatherobservation
    {
        public int Elevation { get; set; }
        public float Lng { get; set; }
        public string Observation { get; set; }
        public string Icao { get; set; }
        public string Clouds { get; set; }
        public string DewPoint { get; set; }
        public string CloudsCode { get; set; }
        public string Datetime { get; set; }
        public string CountryCode { get; set; }
        public string Temperature { get; set; }
        public int Humidity { get; set; }
        public string StationName { get; set; }
        public string WeatherCondition { get; set; }
        public int WindDirection { get; set; }
        public int HectoPascAltimeter { get; set; }
        public string WindSpeed { get; set; }
        public float Lat { get; set; }
    }

}

En el siguiente post, nos enfocaremos a crear e ViewModel correspondiente a la aplicación.

El proyecto con los cambios que vayamos haciendo lo pueden encontrar aquí.

Saludos.

Xamarin Forms: El método Device.OnPlatform

Cuando trabajamos en un desarrollo multiplataforma, a veces es necesario que ciertas propiedades se comporten de forma diferente de acuerdo a la plataforma en la que se encuentre ejecutándose.

Una clase que nos puede ayudar a alcanzar dicho objetivo, es la clase estática Device, la cual dentro de sus métodos incluye un método llamado OnPlatform, cuya definición indica que “Ejecuta diferentes acciones dependiendo en el Xamarin.QcuikUI.TargetOS Form que se encuentre ejecutando.

Es decir, que con dicho método, podremos asignar que una propiedad Text aparezca con un texto diferente en cada plataforma, que un tamaño de letra sea diferente en cada plataforma, etc.

La documentación indica que los parámetros de dicho méotod, son opcionales y van ordenados de la siguiente forma:

iOS
(optional) The Action to execute on iOS.
Android
(optional) The Action to execute on Android.
WinPhone
(optional) The Action to execute on WinPhone.
Default
(optional) The Action to execute if no Action was provided for the current OS.

Veamos un ejemplo práctico con un proyecto recién creado en Xamarin Forms:

            MainPage = new ContentPage
            {
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    Children = {
                        new Label {
                            XAlign = TextAlignment.Center,
                            Text = "Welcome to Xamarin Forms!"
                        }
                    }
                }
            };

El código anterior, muestra el código que es creado en un nuevo proyecto tipo Xamarin Forms, lo modificaremos para que muestre un texto de acuerdo a la plataforma en específico:

                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    Children = {
                        new Label {
                            XAlign = TextAlignment.Center,
                            Text = Device.OnPlatform("IOS", "ANDROID", "WINPHONE")
                        }
                    }
                }

O podemos hacer que un control sea o no visible de acuerdo a la plataforma:

                        new Label {
                            XAlign = TextAlignment.Center,
                            Text = "Welcome to Xamarin Forms!",                            
                            IsVisible = Device.OnPlatform(true,false,true)
                        }

Incluso, podemos implementar un manejador de eventos distinto para un botón en cada plataforma:

            var button1 = new Button
            {
                Text = "Click Me!"
            };
            Device.OnPlatform(
                iOS: () => button1.Clicked += (sender, e) =>
                {
                    DisplayAlert("IOS", "Estoy en un Iphone!", "Ok");
                },
                Android: () => button1.Clicked += (sender, e) =>
                {
                    DisplayAlert("Android", "Estoy en un Androide!", "Ok");
                },
                WinPhone: () => button1.Clicked += (sender, e) =>
                {
                    DisplayAlert("WinPhone", "Estoy en un Lumia!", "Ok");
                }
            );

 

Espero que les sea de utilidad

 

¡Saludos!