What is Xamarin?
We can’t just create an Android project and start writing C# in it. That would be crazy! Right? We need some kind of wrapper or framework for that. You may have heard of a JavaScript framework called Cordova which allows you to write cross platform mobile apps using the web stacks (HTML, CSS, JavaScript). Likewise, now we can also make cross platform apps with C# using Xamarin framework. Xamarin provides three solution templates to build mobile apps:
Xamarin.iOS
(Only for making iOS apps. Use storyboard to design UI and connect that to your C# code behind instead of Objective C or Swift) Xamarin.Android
(Only for making Android apps. Use AXML for UI designing whereas you will use C# as code behind instead of Java as backend code ) Xamarin.Forms
(For making apps for iOS, Android and Windows. Framework provides a set of UI components for creating layout that can be shared across multiple platforms. Use XAML for UI designing and C# as code behind.)
Why Xamarin.Forms?
I’m using Xamarin.Forms
for the demo which I’ll demonstrate soon. Reason behind choosing Xamarin.Forms
is I’m a Windows phone developer (guilty of charge) which means I already know XAML. Other than that, I’m a huge fan of code sharing which means I like to write code once and get it working in all the possible platforms. If you want to know more about Xamarin, you can go to their official site here.
What Are We Building?
Xamarin.Forms
is a great choice for building data driven apps. So let’s make one. Let’s make an app which will show all the characters from STAR WARS movies in a ListView
. I found a free API online (https://swapi.co/) from where I can get all the movie characters in a JSON format from here.
Building the App
Open up the Xamarin Studio. Create a new Xamarin.Forms
app. Give your app a name. You can keep the Identifier as it is. If you are on a MAC, you will have the iOS checkbox enabled for you. Since I’m on Windows, I can only target the Android platform. Select portable or shared class library in the Shared Code section. Finish the next steps.
After you create the solution, you will have three projects in your solution. One for the shared code (starwars), one for the Android app and the last one as the name goes is a UI testing project for your app. Just set the starwars.Droid
as a startup project and run your app.
Before plugging all bits and pieces of the app, let’s discuss some of the basics of this skeleton app. So where this “Welcome to Xamarin Forms!” is coming from? If you go to the startwars.cs file, you will see the exact reason of this magic! In the App()
constructor, we have set the MainPage
(the starting page) property to a newly instantiated ContentPage
. This is one of many built in classes that Xamarin gives us to build the UI of our app. Everything else inside ContentPage
is self-explanatory. We added a StackLayout
to the Content
property. StackLayout
is used to place your controls in a stack on the ContentPage
. The StackLayout
itself is vertically centered (VerticalOptions = LayoutOptions.Center
) on the page. We have a Label
which is used for showing raw text as child to the StackLayout
. And the text is aligned in the center (XAlign = TextAlignment.Center
) of the Label
. I’ve mapped the whole code to the output layout so that you have a good understanding of what is happening.
We can add a standalone ContentPage
in the project and mimic all these things with XAML. So, right click and add a new file to the shared project. Select the “Forms ContentPage Xaml” from the list. Since this is where I’ll show all the STAR WARS characters, I named it SWCharacters
.
After adding, we’ll have an XAML document with a connected C# code behind.
If you notice carefully, you will see that we have a ContentPage
and the Content
node set up for us. Time to add the other pieces we are missing.
As you can see, I’ve added the equivalent XAML markup for the view. Now, we can remove all the codes attached to the MainPage
property and attach a new instance of our newly created ContentPage
. Save everything and give your app a spin. You will have the same result as before.
Enough with the basics. Let’s get back to our app. We need to make a HTTP call to the API (https://swapi.co/people) to get all the characters. To do that, we need to add the Microsoft HTTP Client Libraries package
. We also need the Json.NET
which will help us in parsing raw JSON data to class objects. Search and add both of those in your project from Nuget (Select the shared project > Go to “Project” menu from top menu bar > Add Nuget Packages).
Go to the SWCharacters
code behind (SWCharacters.cs) and add these lines of code given below:
public ObservableCollection<people> Peoples { get; set; }
private HttpClient _client;
private const string PeopleDataUrl = "http://swapi.co/api/people";
public SWCharacters ()
{
InitializeComponent ();
Peoples = new ObservableCollection<people>();
}
public async Task GetAllCharacters()
{
try
{
_client = new HttpClient();
var response = await _client.GetStringAsync(PeopleDataUrl);
if (!string.IsNullOrEmpty(response))
{
var data = JsonConvert.DeserializeObject<rootobject>(response);
foreach (var people in data.Peoples)
{
Peoples.Add(people);
}
}
}
catch (Exception)
{
await DisplayAlert("Error", "Something went wrong", "Ok");
}
}
private async void PeopleButton_OnClicked(object sender, EventArgs e)
{
GetAllCharacters();
}
I’ve grabbed all the characters through a HTTP ‘GET
’ call to https://swapi.co/people and serialized into an ObservableCollection
(an extended version of the List
class in C#) of People
objects using Json.Net’s JsonConvert.DeserializeObject
. To know more about serialization, you can read this blog post of mine here - http://fiyazhasan.me/serialization-for-fun/. Here is the serialized object class that I was talking about. The attributes ([JsonObject("Result")]
, [JsonProperty("results")
] are used only for giving those classes and properties a generic name.
People.cs
[JsonObject("Result")]
public class People
{
public string name { get; set; }
public string height { get; set; }
public string mass { get; set; }
public string hair_color { get; set; }
public string skin_color { get; set; }
public string eye_color { get; set; }
public string birth_year { get; set; }
public string gender { get; set; }
public string homeworld { get; set; }
public string created { get; set; }
public string edited { get; set; }
public string url { get; set; }
}
public class RootObject
{
public int count { get; set; }
public string next { get; set; }
public object previous { get; set; }
[JsonProperty("results")]
public List<people> Peoples { get; set; }
}
Now, you can ask me where I got this class from. It’s really easy to generate class objects for serialization. I went to the https://swapi.co/ and initiate a request to their https://swapi.co/people API. I copied the JSON result. Then I went to this site - http://json2csharp.com/ and pasted my JSON to get the appropriate class objects. See the images below:
I’ve created a class file in my project and paste those two classes inside that. I’m done here. You can see a PeopleButton_OnClicked
event in the SWCharacters.cs. That’s because I wanted to initiate the HTTP call only when I click on that button from the UI. Here is new XAML markup for the app that creates the button.
<ContentPage.Content>
<StackLayout VerticalOptions="Center">
<Button x:Name="PeopleButton"
Text="Get People" Clicked="PeopleButton_OnClicked"></Button>
</StackLayout>
</ContentPage.Content>
Now if you run the project and click on the button, you will get the people data from the API. The button is only for checking whether we have a successful call to the API or not. I’ve placed some debug points and check if everything’s okay or not.
Next, we will replace the button with a ListView
control and attached its ItemSource
property to our ObservableCollection
of people. Replace your previous XAML markup with the following:
<ContentPage.Content HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout>
<ListView x:Name="PeopleListView" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Label Text="{Binding name}"
FontSize="16" Grid.Row="0"></Label>
<Label Text="{Binding height}"
Grid.Row="1"></Label>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
So, we have a ListView
instead of the button we previously had. To set the look and feel of the items added to the ListView
, we have ListView.ItemTemplate
. To be able to bind controls inside a ListView.ItemTemplate
to appropriate list item’s properties, we have DataTemplate
. ViewCell
is one of the many Cell controls of Xamarain. ViewCell
is used just for showing raw data, you can use EntryCell
if you want textbox
control as a part of your list item. I’ve placed another Grid
layout inside ViewCell.View
and last of all added two Labels
. One of the Label
is bound to the name
property of the character while the second one is bound to the height
property. The new code behind looks like below:
public partial class SWCharacters : ContentPage
{
public ObservableCollection<people> Peoples { get; set; }
private HttpClient _client;
private const string PeopleDataUrl = "http://swapi.co/api/people";
public SWCharacters ()
{
InitializeComponent ();
Peoples = new ObservableCollection<people>();
GetAllCharacters();
}
public async Task GetAllCharacters()
{
try
{
_client = new HttpClient();
var response = await _client.GetStringAsync(PeopleDataUrl);
if (!string.IsNullOrEmpty(response))
{
var data = JsonConvert.DeserializeObject<rootobject>(response);
foreach (var people in data.Peoples)
{
Peoples.Add(people);
}
PeopleListView.ItemsSource = Peoples;
}
}
catch (Exception)
{
DisplayAlert("Error", "Something went wrong", "Ok");
}
}
}
Since I’ve removed the button from the view, so I also deleted the event handler associated with that and initiate the HTTP request from the main constructor. Again, I’ve bound the ItemSource
property of our ListView
to the observable collection I talked about (PeopleListView.ItemsSource = Peoples;
). Now if you run this project, after a while you will get the character list with the name
and height
property shown on the respective labels.
What You Should Be Concerned About?
To make this demo project simple and easy to understand, I’ve done some things against the rules. Like I called an asynchronous process from the constructor. Which is definitely bad! You can search the web and follow best practices in writing asynchronous code. Again, I wrote a whole lot of code in the XAML code behind. Basically in real life, you would follow pattern like MVVM which will omit this code from the UI backend and make you app unit testable.
Downloading and Running the App
Download the solution as a zip format. Unzip it and open it in your Xamarin Studio. I’ve removed all the packages .dll files from the project. So you will need to restore the packages. Just like you added a nuget package in the project, restore the packages from the option right below it.
What's Next?
These are some of the basics of building apps with Xamarin Forms. Consider this as a “Hello World
” program. Download the project and add some more functionalities like a detail page for a specific character, add a loading indicator to allow user to know that you are downloading stuff from the internet. Again play with the APIs available on https://swapi.co/ and make a full-fledged STAR WARS fan app. You can find a whole lot of control available for you to use here - https://developer.xamarin.com/guides/cross-platform/xamarin-forms/controls/. Follow Xamarin’s API documentation if you are stuck anywhere. Have fun and I’ll see you in the next post. Bye bye geeks!