Saturday, November 5, 2016

Xamarin Forms Client for Azure ASP.NET Web API service

Xamarin Forms allows for the development of mobile apps using C# with a single code base for deployment to Android, iOS, and Windows.

It is advisable that you watch this video on Channel 9 in order to properly setup your Visual Studio 2015 environment for Xamarin development:

https://channel9.msdn.com/series/tendulkar-uvca/0102-Verify-Machine-Setup

Overview

The objective of this tutorial is to consume a Web API service. In this tutorial, we will use a service at http://cartoonapi.azurewebsites.net/api/cartoon. If you point your browser to this address, the JSON response will look like this:

[{"name":"Aladdin","pictureUrl":"images/aladdin.png"},
{"name":"Bambam Rubble","pictureUrl":"images/bambam_rubble.png"},
{"name":"Bambi","pictureUrl":"images/bambi.png"},
{"name":"Barney Rubble","pictureUrl":"images/barney_rubble.png"},
{"name":"Betty Flintstone","pictureUrl":"images/betty_flintstone.png"},
{"name":"Dino","pictureUrl":"images/dino.png"},
{"name":"Donald Duck","pictureUrl":"images/donald_duck.png"},
{"name":"Flintstone Family","pictureUrl":"images/flintstone_family.png"},
{"name":"Flounder","pictureUrl":"images/Flounder.png"},
{"name":"Fred Flinrstone","pictureUrl":"images/fred_flinrstone.png"},
{"name":"Goofy","pictureUrl":"images/Goofy.png"},
{"name":"Jasmine","pictureUrl":"images/jasmine.png"},
{"name":"Jumbo","pictureUrl":"images/jumbo.png"},
{"name":"Mermaid","pictureUrl":"images/mermaid.png"},
{"name":"Micky Mouse","pictureUrl":"images/micky_mouse.png"},
{"name":"Minnie Mouse","pictureUrl":"images/minnie_mouse.png"},
{"name":"Pebbles Flintstone","pictureUrl":"images/pebbles_flintstone.png"},
{"name":"Peter Pan","pictureUrl":"images/peter_pan.png"},
{"name":"Pinocchio","pictureUrl":"images/pinocchio.png"},
{"name":"Pluto","pictureUrl":"images/pluto.png"},
{"name":"Simba","pictureUrl":"images/simba.png"},
{"name":"Snow White","pictureUrl":"images/snow_white.png"},
{"name":"Tigger","pictureUrl":"images/tigger.png"},
{"name":"Tinkerbell","pictureUrl":"images/tinkerbell.png"},
{"name":"Tweety","pictureUrl":"images/tweety.png"},
{"name":"Wilma Flintstone","pictureUrl":"images/wilma_flintstone.png"},
{"name":"Winnie The Pooh","pictureUrl":"images/winnie_the_pooh.png"}]


The above JSON collection pertains to cartoon characters with only two properties: Name & PictureUrl.

Creating a Xamarin Forms portable application

Start Visual Studio 2015 then click on:

File >> New >> Project
Templates >> Visual C# >> Cross-Platform >> Blank Xaml App (Xamarin.Forms Portable)

image

Name the application “ComicMobile” then click on OK.

On the “New Universal Windows Project” dialog, choose Build 10586 for both Target and Minimum versions.

image

Be patient, it may take some time to create these six projects:

ComicMobile This is a shared solution
ComicMobile.Droid Android project
ComicMobile.iOS iOS project
ComicMobile.UWP UWP project
ComicMobile.Windows Windows 8.1 project
ComicMobile.WinPhone Windows Phone 8.1 project

Go ahead and remove the last two projects (ComicMobile.Windows & ComicMobile.WinPhone) from the Visual Studio solution in order to keep our project as small as possible. Also, delete the relevant folders for the two projects that you removed from the file system.

Open the configuration manager by selecting Build >> Configuration Manager…

image

Enable Build & Deploy for the UWP project then click on Close.

Right-click on the UWP project and select Build.

Then, right-click again on the UWP application and select “Set as StartUp Project”.

Hit F5 on the keyboard to run the UWP application in debug mode on the “Local Machine”. The application will run and the main window will look like this:

image

Adding a Web API client

Close the running application, then install the following two Nuget package to the “ComicMobile (Portable)” project:

Newtonsoft.Json
Microsoft.Net.Http

Add folders Models and ViewModels to the top “ComicMobile (Portable)” project.

Add a class named CartoonCharacter to the Models folder. In order to put  remote data into a C# collection, replace the CartoonCharacter class definition in the Models folder with the following code:

public class CartoonCharacter {
  public string Name { get; set; }
  public string PictureUrl { get; set; }
}


The code for actually connecting to the remote service and reading data will be placed in a View Model class. Add a class named CartoonViewModel to the ViewModels folder and replace the class definition with the following code:

public class CartoonViewModel : INotifyPropertyChanged {
  const string BASE_URL = "
http://cartoonapi.azurewebsites.net/";
  public event PropertyChangedEventHandler PropertyChanged;
  public Command GetCartoonCharactersCommand { get; set; }

  public ObservableCollection<CartoonCharacter> CartoonCharacters { get; set; }
  public CartoonViewModel() {
      CartoonCharacters = new ObservableCollection<CartoonCharacter>();

      GetCartoonCharactersCommand = new Command(
        async () => await GetCartoonCharacters(),
        () => !IsBusy);
  }

  private void OnPropertyChanged([CallerMemberName] string name = null) =>
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

  private bool busy;
  public bool IsBusy {
    get { return busy; }
    set {
      busy = value;
      OnPropertyChanged();
      //Update the can execute
      GetCartoonCharactersCommand.ChangeCanExecute();
    }
  }

  private async Task GetCartoonCharacters() {
    if (IsBusy)
        return;

    Exception error = null;
    try {
      IsBusy = true;

      using (var client = new HttpClient()) {
        //grab json from server
        var json = await client.GetStringAsync(BASE_URL + "api/cartoon");

        //Deserialize json
        var items = JsonConvert.DeserializeObject<List<CartoonCharacter>>(json);

        //Load speakers into list
        CartoonCharacters.Clear();
        foreach (var item in items) {
          CartoonCharacters.Add(new CartoonCharacter() {
            Name = item.Name,
            PictureUrl = BASE_URL + item.PictureUrl
          });
        }
      }
    } catch (Exception ex) {
      Debug.WriteLine("Error: " + ex);
      error = ex;
    } finally {
      IsBusy = false;
    }

    if (error != null)
      await Application.Current.MainPage.DisplayAlert("Error!", error.Message, "OK");
  }
}


Resolve any missing namespaces then compile your application to make sure you do not have any errors.

Adding UI to our application

We will need to add some UI to our portable project as follows:
  • Open MainPage.xaml and delete the <Label …> tag.
  • Put the following XAML markup between the opening and closing <ContentPage …> tags:
<StackLayout Spacing="0" Padding="20,20,0,0">
  <Button Text="Get Cartoon Characters"
    Style="{StaticResource buttonStyle}"
    Command="{Binding GetCartoonCharactersCommand}"/>
  <ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}"/>
  <ListView x:Name="ListViewCartoonCharacters"
       ItemsSource="{Binding CartoonCharacters}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <TextCell Text="{Binding Name}"/>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</StackLayout>


The above XAML markup just adds a button and a list. When the button is clicked, our application will retrieve data from a remote Web API service, then it will populate the list.
The button is bound to a method called GetCartoonCharactersCommand, which is already defined in our CartoonViewModel class.
  • Our UI uses a button style named buttonStyle. Add the following markup to App.xaml between the opening and closing <Application.Resources> tags:
<ResourceDictionary>
  <Style x:Key="buttonStyle" TargetType="Button">
    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
    <Setter Property="BorderColor" Value="Black" />
    <Setter Property="BorderRadius" Value="3" />
    <Setter Property="BorderWidth" Value="3" />
    <Setter Property="WidthRequest" Value="200" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="BackgroundColor" Value="Silver" />
  </Style>
</ResourceDictionary>

  • To bind our MainPage.xaml UI to the CartoonViewModel , add the following code to bottom of the MainPage() constructor in MainPage.xaml.cs, right under InitializeComponent();
//Create the view model and set as binding context
CartoonViewModel vm = new CartoonViewModel();
BindingContext = vm;

  • Let’s test out the application. Build and run it. You should see a window that looks like this:
image
  • Click on the “Get Cartoon Characters” button. It will retrieve the names of cartoon characters on the server:
image

Adding a details page

To enhance our application, we will build the feature so that when a user click on a particular cartoon character, it displays an image of that character in a separate page. It addition, it will allow the user to go to a webpage that displays the image.
  • We need to add an event handled in MainPage.xaml.cs that handles the item selection process. Add the following code to the bottom of the MagePage() constructor in MainPage.xaml.cs:
ListViewCartoonCharacters.ItemSelected += ListViewCartoonCharacters_ItemSelected;
  • Next, add the code for handling the event by adding this method to the MainPage class in MainPage.xaml.cs:
private async void ListViewCartoonCharacters_ItemSelected(object sender, SelectedItemChangedEventArgs e) {
  var character = e.SelectedItem as CartoonCharacter;
  if (character == null)
      return;

  await Navigation.PushModalAsync(new DetailsPage(character));
  ListViewCartoonCharacters.SelectedItem = null;
}


Note that an object is being passed in the constructor of a page DetailsPage, which we are about to create.
  • To the ComicMobile project, add a “Forms Xaml Page” and name it DetailsPage.xaml.
image
  • In DetialsPage.xaml, replace the <Label …> tag with the following XAML markup:
<ScrollView Padding="10">
  <StackLayout Spacing="10" >
    <!-- Detail controls here -->
    <Image Source="{Binding PictureUrl}" HeightRequest="200" WidthRequest="200"/>

    <Label Text="{Binding Name}" FontSize="24" HorizontalTextAlignment="Center"/>
    <Button Text="Show image on Website" x:Name="ButtonWebsite" Style="{StaticResource buttonStyle}"/>
  </StackLayout>
</ScrollView>

  • Add the following instance variable to the DetailsPage class in DetailsPage.xaml.cs:
CartoonCharacter _cartoonCharacter;
  • Replace the DetailsPage() constructor with the following code that takes a CartoonCharacter as an argument:
public DetailsPage(CartoonCharacter cartoonCharacter) {
  InitializeComponent();

  //Set local instance of speaker and set BindingContext
  this._cartoonCharacter = cartoonCharacter;
  BindingContext = this._cartoonCharacter;

  ButtonWebsite.Clicked += ButtonWebsite_Clicked;
}

  • Add the following event handler method to the DetailsPage class to handle the button click for viewing a webpage:
private void ButtonWebsite_Clicked(object sender, EventArgs e) {
  if (_cartoonCharacter.PictureUrl.StartsWith("http"))
    Device.OpenUri(new Uri(_cartoonCharacter.PictureUrl));
}

  • Build and run your application.
image
  • Click on the “Get Cartoon Characters” button.
image
  • Click on a name like “Donald Duck”.
image
  • Click on the “Show image on Website” button. It will open a web page in your browser that just displays the image:
image

Android

Try running this same application in the Visualk Studio 2015 Android emulator by making the Android project (ComicMobile.Droid) your startup application.

image
image
image

a single code base, we were able to develop an app that runs on Android, iOS, and Windows. This is the power of Xamarin Forms.

No comments:

Post a Comment