Xamarin.Forms: from zero to hero – part 2

Xamarin.Forms: from zero to hero – part 2

In my previous post I have covered the basics of starting with Xamarin, more specific Xamarin.Forms. There I have described that my first app would be a business app for the company I work for.

In the meanwhile I have been working on this app to get it ready for the App Store, Market and/or Play Store. In this continuing post I will put things in perspective for you and describe how the app has taken shape, which decisions I’ve made (and why) and the sleepless nights I’ve had because of stuff that didn’t work.

First let’s refresh your memory a bit. No need? Just skip to the next heading then!

Previously on As The World Blogs…

In the post before this I have told you about the different project templates you get to choose from to build a Xamarin app.

With the little knowledge I had upfront I knew I wanted to use XAML for my markup, the app had to be as multi-platform as can be, the code base had to be shared as possible and because it was a first for me with Xamarin I didn’t want to do a lot of fancy stuff right away.

Wishlist for the first version:

  • General description of what we do how and why we do it at all;
  • Overview of the employees and some details about them;
  • Contact information.

After applying some common sense I figured that since I was creating a digital business card of sorts, the main goal – as a end-user –  would be to be able to contact us ASAP and – as a company – create possible sales opportunities.

The first ‘requirement’ would be easy to solve. Just incorporate a call and e-mail button on every page elegantly. The user would be able to contact us from anywhere within the app when they are (finally) convinced of our epic skills.

The second one wasn’t really a goal in itself, but by providing relevant and fun content in a sexy UI I would hope to persuade potential customers to choose for us.

So far for the outline. Make it so!

Buckle your seatbelt Dorothy, ‘cause Kansas is going bye-bye!

Because of my research I knew what project template to choose to satisfy my needs. So start Visual Studio, create a new project, give it a name and wait a while for all the projects to be generated.

The name of the company I work for is 4DotNet which, as it turns out, is a toughie while coding because you can’t start class names and variables etc. with a number. So as a solution name I choose FourDotNet to get around it.

On to my first screen. The first question arises: what layout to choose?
As we saw in my last post there are a number of different pages already provided by Xamarin.

Xamarin.Forms Pages
Xamarin.Forms Pages

The ContentPage seemed a little to marginal for the goals I wanted to achieve. The MasterDetailPage is a viable option, but since the app won’t have too much content, the ways to navigate within a MasterDetailPage seemed to devious.
NavigationPage manages a stack of pages, doesn’t fit for now.. TabbedPage.. Bingo! This looks like the thing I want!
Let’s check out the CarouselPage just in case. Also awesome but for me the CarouselPage feels too much like the native Panorama Windows Phone control.

So the TabbedPage it is.

First thing I did was create a XAML page, MainPage.xaml, in the shared project, FourDotNet, and change the App.cs to use is.
To keep things neat I’ve created a folder to contain my pages instead of just putting them in the root.
After I did this my FourDotNet project looks like this:

[SPOILER ALERT] I’ve already created some more pages in the screenshot underneath.

FourDotNet Project tree
FourDotNet Project tree

And the code in my App.cs looks like this:

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

Of course don’t forget to include the right namespaces and for your convenience I’ve omitted the rest of the methods in the class. We’ll leave them there for now.

The standard XAML page contains just a ContentPage with a centered label, what we are after is a TabbedPage with three tabs. So let’s open up the MainPage.xaml and start editing.

The start and end <ContentPage> tag we modify to <TabbedPage>, lose the label and replace it with Children of the ContentPage.
After we’re done with it, this is what is looks like:

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:pages="clr-namespace:FourDotNet.Pages;assembly=FourDotNet" x:Class="FourDotNet.Pages.MainPage">
  <TabbedPage.Children>
  </TabbedPage.Children>
</TabbedPage>

The children of a TabbedPage, which will become the actual tabs, can be any type of other pages. So let’s create some.

As you may have noticed I already created a few in the screenshot above. For the tabs I will be using:

  • GeneralPage: a page with just a description;
  • EmployeesPage: a page with a list of our wonderful employees;
  • LocationPage: a page showing a map with our locations and some contact information.

We can create these pages like we did with the first one, and of course in our Pages folder.

GeneralPage.xaml

Let’s start off with the GeneralPage. As described before, this will contain just a text about the company. So probably a simple ContentPage will suffice here.

Not having worked with Xamarin before left a little clueless here. How am I going to show just a text which at the same time should contain markup to make it readable?

Let’s check the documentation page and walkthrough the most feasible options.

WebView

First I turned to a WebView. With this I could load a external URL, but I would have to create a single page with styling, etc. which only purpose would be to be shown in the app. Also I would have to think about some sort of caching mechanism so it would show whenever the user has no internet connection available. On the other hand I could update the text remotely without rebuilding and updating the app itself.
I could also create a local web page which is loaded into the WebView. I would still have to create a wellformed page, dito CSS styling, include it into each project separately (or do research on sharing resources).

Maybe later. There are probably other, maybe better, options.

Label

The association I have with a Label is that it contains only a small portion of text. A full sentence at most. But maybe I’m wrong. It could, of course, contain more text. And also, why would I limit myself to use just one label? I could have several and layout however I want them. Because let’s not forget that I also have the Layout controls at my disposal.

I’m gonna go with labels in a StackLayout for now. A StackLayout just stacks the controls vertically or horizontally. Also you can nest them, which enables you to create a ‘row’ with a number of horizontal controls and wrap it in a vertical StackLayout to stack things under it as well. Or the other way around.

With the StackLayout and labels I was able to create a text with some headers and a describing text underneath. This would fulfill my needs for now. The header labels will have another color and be slightly bigger. Underneath you can see the XAML and resulting page in the (iOS) emulator.
For TL;DR purposes I’ve replaced the actual texts with the word ‘Text’.

MainPage.xaml iOS screenshot
MainPage.xaml iOS screenshot
<?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="FourDotNet.Pages.GeneralPage">
  <ScrollView>
    <StackLayout>
      <Label FontSize="Large" TextColor="#0092DB">
        Wat doen we?
      </Label>
      <Label FontSize="Small">
        Text
      </Label>
      <Label FontSize="Large" TextColor="#0092DB">
        Hoe doen we het?
      </Label>
      <Label FontSize="Small">
        Text
      </Label>
      <Label FontSize="Large" TextColor="#0092DB">
        Waarom doen we het?
      </Label>
      <Label FontSize="Small">
        Text
      </Label>
      <Label FontSize="Large" TextColor="#0092DB">
        Wie zijn wij?
      </Label>
      <Label FontSize="Small">
        Text
      </Label>
    </StackLayout>
  </ScrollView>
</ContentPage>

One thing you can’t capture in an image, but was in fact a problem that presented itself, was the fact that this LabeledStackLayoutPage™ couldn’t scroll!

Luckily while going through the Xamarin documentation pages I came across the ScrollView. Wrapping this around the StackLayout made it work at the first try. Awesome!

Another thing that is noticeable is that the text runs behind the statusbar. If we look at the same screen in Windows Phone it looks fine.

MainPage.xaml Windows Phone screenshot
MainPage.xaml Windows Phone screenshot

So it seems that we have platform specific behaviour going on here. Windows Phone (and Android, take it from me) apparently see the statusbar as something you either hide or, when it is visible, a space that cannot be used. While iOS let’s you happily draw from top to bottom. So we have to define a padding, but just for iOS.

In XAML we can do it like this:

<?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="FourDotNet.Pages.GeneralPage">
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness">
      <OnPlatform.iOS>
        20, 20, 20, 0
      </OnPlatform.iOS>
    </OnPlatform>
  </ContentPage.Padding>
...
</ContentPage>

When you want to have different values for another platform as well you can extend it like so:

<ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness">
      <OnPlatform.iOS>
        0, 20, 0, 0
      </OnPlatform.iOS>
      <OnPlatform.Android>
        0, 0, 0, 0
      </OnPlatform.Android>
      <OnPlatform.WinPhone>
        0, 0, 0, 0
      </OnPlatform.WinPhone>
    </OnPlatform>
  </ContentPage.Padding>

If the value can be represented by a simple string (like the above) you can also define them like this:

<ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness"
                iOS="0, 20, 0, 0"
                Android="0, 0, 0, 0"
                WinPhone="0, 0, 0, 0" />
</ContentPage.Padding>

It will look all the same, so this would just be a matter of taste.

With this you cannot just add some padding, also you can provide a custom background or platform specific icons.

Besides the OnPlatform tag we also have a OnIdiom tag with which you can specify the type of device (phone or tablet) rather than the actual platform.

For now that concludes my first screen. On to the next one, the list of employees!

EmployeesPage.xaml

Let’s create another clean page. Again, this gives is the centered label which I quickly and swiftly will replace with a ListView. Because I wanted to show a list of our employees, I have stopped searching for a better control when I came across a control that states ‘List’ in the name.

The rest seemed pretty straight forward: get a list of employees somewhere online, retrieve it, show it in the the list and when a employee is tapped (nasty..) show some details.

Here I ran into some problems, nothing we can’t handle but some things you should know about!

One does not simply get all the employees

Luckily we just got a new website which also lists all of our employees and the skills that comes with them, so that came in quite handy! From there I was able to create a JSON feed which I would be able to retrieve within the app.

Being able to use the standard .Net goods in Xamarin I downloaded the Json.Net NuGet package and created some code to get the employees to my app.

I ran into some trouble right then and there. Not even handling the JSON, but rather acquiring the JSON itself from the website. On projects before I have leveraged the WebClient to download a string and work from there.

But the project created by Xamarin is as much backwards compatible as possible, which means it also targets Windows Phone 8. The same Windows Phone 8 that doesn’t support this particular class.

So here you have to choose whether to drop support on Windows Phone 8 (which probably isn’t used very much anyway) or find some other way.

Because it is a simple app and has to reach as much audience as possible, I decided to take the hard way and find another solution.

This involves creating a WebRequest yourself and define a callback method to handle the response.
The WebRequest simply looks like this;

var req = WebRequest.CreateHttp("http://www.4dotnet.nl/medewerkers/");
//req.ContentType = "application/json";
req.Accept = "application/json";
req.Method = "GET";

req.BeginGetResponse(EmployeeResponseCallback, req);

Note that you have to define the request as a HTTP GET request and set the Accept header to ‘application/json’. At a first attempt I stated the WebRequest to have a Content-Type of ‘application/json’, commented out in the above snippet.
Oddly enough this works for iOS, but when I ran this on Windows Phone I got an exception which told me that a GET request cannot have a body.
This puzzled me at first. I didn’t have any body in my request, so why is it telling me I have?!
After a quick search I found that setting the Content-Type on the request implied that there is, in fact, a body even if it is empty. Like I said, weird enough it only seems to cause problems on Windows Phone. Besides that I should set the Accept and not the Content-Type.

Below is the code I have in my callback.

var request = (HttpWebRequest) result.AsyncState;
var response = request.EndGetResponse(result);

using (var stream = response.GetResponseStream())
{
  using (var reader = new StreamReader(stream))
  {
     var jsonDoc = JsonConvert.DeserializeObject<EmployeeContainer>(reader.ReadToEnd());

     _container.Employees.Clear();

     foreach (var employee in jsonDoc.Employees.OrderBy(e => e.Name))
     {
        _container.Employees.Add(employee);
     }
  }
}

Here you will notice something which doesn’t seem very performing. I clear out a collection and fill it again with a for-each loop.
For my list I decided to use data-binding. In my XAML that looks like this:

<?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="FourDotNet.Pages.EmployeesPage"
             Title="Medewerkers">
  <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand">
	<ListView IsPullToRefreshEnabled="True" Refreshing="EmployeeListView_OnRefreshing" ItemTapped="EmployeeListView_OnItemTapped" x:Name="EmployeeListView">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ImageCell ImageSource="{Binding PhotoUrl}" Text="{Binding Name}" Detail="{Binding Function}">          
          <ImageCell.ContextActions>
            <MenuItem Text="Stuur e-mail" Clicked="EmployeeContextEmail_OnClicked"></MenuItem>
          </ImageCell.ContextActions>
        </ImageCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
  </StackLayout>
</ContentPage>

Notice that I didn’t have to do anything fancy and just use the standard data-binding thingies.

Also; as a bonus you can see I’ve added ContextActions. I won’t go explaining them here, make it a challenge for yourself!

Because of the data-binding I also use a ObservableCollection. If you have some experience with this you probably know that I cannot just exchange one collection for another, but I have to modify the existing collection in order to keep the binding working.

Eureka! It works! My list shows and fills and because of the built in ‘drag down to refresh’ support on the ListView it refreshes nicely when I pull the list all the way down. Again, something to explore on your own. It’s not hard!

But now I wanted more, when I choose an employee it should advance to another page and show that employee in more detail. Which led me to navigation.

Page navigation (EmployeePage.xaml)

For navigating through pages each platform has it’s own mechanism, but the final results are more or less the same.
Navigation is basically just a stack of pages that you can push a page onto (to show it) and pop pages off (to ‘close’ it). There are also some possibilities to show something modal, or remove pages from down the stack, but for now it seems that when I tap a employee I want to push his or her page onto the stack, and when the user goes back I would want to pop it and show the previous page.

Before continuing I will have you know that I have created yet another XAML page, the EmployeePage.xaml, which will serve as a detail page for showing one employee.

My first attempt was pretty straightforward:

private async void EmployeeListView_OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
   var selectedItem = (Employee)e.SelectedItem;

   var employeePage = new EmployeePage(selectedItem);
   await Navigation.PushAsync(employeePage, true);

   EmployeeListView.SelectedItem = null;
}

This involved wiring the ItemSelected on the ListView and within the event push a page onto the navigation stack. Running this code immediately gave me a run-time exception. Although it only seems to occur on iOS.

NavigationPage Exception
NavigationPage Exception

As it turns out, when you want to do navigation like this, you have to start pushing pages onto the stack right from the beginning. So what I had to do was go into my App.cs and wrap my MainPage in a NavigationPage like so:

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

When you now start the application, something has changed. Wrapping your page in a NavigationPage also gave you a free navigation bar at the top of the screen!

Now when we push the page onto the stack at the point where we choose are employee, it looks like this.

EmployeePage
EmployeePage

Ok, I already added some more information, but eventually it looks like this. You’ll notice that a back button is provided in the navigation bar as you push pages onto the stack.
Now, when you push that back button you will see that the employee you chose is still selected and can’t be selected again until you tapped another one, which then has the same problem.

Trying to fix this I tried to set the selected item on the list to null programmatically. As I already did in the above snippet.
This caused some unwanted behaviour. Setting the selected item to null from within the ItemSelected event caused the event to fire again (doh), but this time with no selected item and so an empty page was shown.

Luckily there is also a ItemTapped event which can do roughly the same. The final code which does what I wanted:

private async void EmployeeListView_OnItemTapped(object sender, ItemTappedEventArgs e)
{
   var selectedItem = (Employee)e.Item;

   var employeePage = new EmployeePage(selectedItem);
   await Navigation.PushAsync(employeePage, true);

   EmployeeListView.SelectedItem = null;
}

As you can see you still need to set the selected item to null. I won’t go in to designing the rest of the employee detail page, you should be able to do so yourself with the knowledge you have gained reading this post. Maybe some more specifics will be described in future articles, or you are of course free to ask me by mail, Twitter, etc.

LocationPage.xaml

Last but not least the page to show our locations. For now I’ll settle for just showing a map with markers on our locations. Later on I probably want to expand the page to show some more info, but I haven’t figured that out just yet.

The map control isn’t present by default, you have to install it as a separate NuGet package.

After installing it you have to add some initialization code to each app as well. The code you have to use is simple;

Xamarin.FormsMaps.Init();

Place this right after the

Xamarin.Forms.Forms.Init();

in each app. For each specific platform you can find it in the following files:

  • iOS – AppDelegate.cs file, in the FinishedLaunching method;
  • Android – MainActivity.cs file, in the OnCreate method;
  • Windows Phone – MainPage.xaml.cs file, in the MainPage constructor.

Furthermore don’t forget that privacy is a big issue these days, so don’t forget to specify that your app is using location services. Mainly you have to do two things: in the properties of your project enable some checkboxes which state that the app will use location services and add an API key of Bing/Google maps to your code.
I won’t get into detail about it here for now, but check the Xamarin documentation on how to do this.

Last but not least there are two pins to be added which point out our location.

public LocationPage()
{
   InitializeComponent();

   const int zoomLevel = 7; // between 1 and 18
   var latlongdegrees = 360 / (Math.Pow(2, zoomLevel));

   var meppelPin = new Pin
   {
      Position = new Position(52.70532069999999, 6.187675799999965),
      Address = "Paradijsweg 2, 7942 HB Meppel",
      Label = "Locatie Meppel",
      Type = PinType.Place
   };

   var nieuwegeinPin = new Pin
   {
      Position = new Position(52.027241, 5.064933300000007),
      Address = "Nevelgaarde 40, 3436 ZZ Nieuwegein",
      Label = "Locatie Nieuwegein",
      Type = PinType.Place
   };

   MainMap.Pins.Add(meppelPin);
   MainMap.Pins.Add(nieuwegeinPin);

   MainMap.MoveToRegion(new MapSpan(new Position(52.50, 5.45), latlongdegrees, latlongdegrees));
}

Declaring the pins and adding them to the map should be pretty straightforward. At the last line I set the center of the map to the center of Holland, hence the coordinates.

Of course, there is some graphic for this page as well;

LocationPage screenshot
LocationPage screenshot

Fin.

This concludes the basics of designing and developing my first Xamarin app. The description in this article isn’t complete. By following all the instructions you won’t have a publish-ready app, but it should give you the first clue on where to start and more important; show you that starting Xamarin doesn’t involve a lot of learning right away. Later on there will be problems challenges, I’m sure. But the basics doesn’t involve much more than you already know; C# and .Net! Awesome!

To finish this app, consider the following;

  • I still need to implement the e-mail and call actions;
  • There is a lot of ‘hidden’ work to find and implement platform specific icons and look-and-feel tweaks. Not in the least the icons and screenshots you need to provide in order for the app to pass the publishing committee and get it into the app store;
  • Testing! Testing! Testing! Not just in the emulator, also on a physical device. I have never designed an app that showed some unwanted behaviour that I didn’t catch in the emulators.

For now: thank you for reading, I’ll promise the future posts will be more bite-sized. Cheers!