Life as a developer

Xamarin.Forms Crash course

I was invited by Microsoft to hold a session at a Xamarin meetup in Oslo, and I was of course happy to oblige. It was a full day event with a few sessions and a workshop at the end of the day. My talk focused on Xamarin.Forms and how one would get quickly up and running building an app.

I have used Xamarin for years, but now I feel the framework is mature enough to use in large scale production apps. Xamarin got a lot of attention the when Microsoft acquired them. Microsoft made Xamarin available for free with Xamarin Studio or Visual Studio Community and made the code open source. With the increased user mass, we can expect increased support, both officially and in other channels like Stack Overflow, Slack or Xamarin forums. Microsoft can now offer a better story to their developers, .Net developers can create apps for just about every platform with C# (or F#).

Xamarin.Forms app

I will show how you can create a simple conference app using Xamarin.Forms.
First

File -> New Solution ...

Select

Forms App

Then there’s the question of whether to use Portable Class Library (PCL) or Shared Library. Xamarin recommends PCL, and so do I. There are various reasons for this, but I my code is easier to test and it gives me an extra comfort knowing that my code is at least compiled, no matter which platform I am targeting.

"Use XAML for user interface files" should be checked, this is also a personal preference. This only sets the the default pages as XAML, you can mix and match XAML and CS files as it pleases you.

If you want UI Tests, you can check "Add an automated UI test project". You can still run your test files locally even if you don’t have a Xamarin Test Cloud subscription.

Start by adding a new Forms ContentPage: LoginPage.

We want to adhere to the MVVM pattern and use ViewModels, so create another folder ViewModels and add a new class, LoginViewModel.

Create a string property for Header and ButtonText.
And a ICommand property for the button action GoToMainCommand.

For now set the Header to “Demo” and ButtonText to “Go to main”.

We want the button to navigate to MainPage, but in order to do that we need access to the built-in navigation service: NavigationService, It can be accessed through the LoginPage. Let’s use constructor injection to inject INavigation service into the viewmodel.

public LoginViewModel(INavigation navigation)

Now that the navigation service is accessible we can use that to navigate to the MainPage.

GoToMainCommand = new Command(async () => 
    await navigation.PushAsync(new MainPage())
);

We want to start with the LoginPage, so change the App.cs:

MainPage = new NavigationPage(new LoginPage());

NavigationPage allows you to navigate between pages and holds a stack of pages that you have visited. You use push and pop for navigating through the stack.

To show off some another feature built in in Xamarin.Forms, I want to make use of DependencyService. Let’s say we want to display different text for iOS and Android, we can use the DependencyService where you can hook up different services based on platform. This is a contrived example, Device.OnPlatform would have been more appropriate for this basic task.

In the PCL project add a new interface, ITextService.

public interface ITextService
{
    string GetTitle();
}

For Android and iOS, add one service for each platform.
Android:

using System;
[assembly:Xamarin.Forms.Dependency(typeof(ConfDemo.Droid.TextService))]
namespace ConfDemo.Droid
{
    public class TextService : ITextService
    {
        public string GetTitle()
        {
            return "Hi from Android";
        }
    }
}

iOS:

using System;
[assembly:Xamarin.Forms.Dependency(typeof(ConfDemo.iOS.TextService))]
namespace ConfDemo.iOS
{
    public class TextService : ITextService
    {
        public string GetTitle()
        {
            return "Hi from iOS";
        }
    }
}

LoginViewModel looks like this:

public class LoginViewModel
{
    public string Header { get; set; }

    public string ButtonText => "Log in";

    public ICommand GoToMainCommand { get; set; }

    public LoginViewModel(INavigation navigation)
    {
        GoToMainCommand = new Command(async () => 
            await navigation.PushAsync(new MainView()));
        var textService = DependencyService.Get(
            DependencyFetchTarget.NewInstance);
        Title = textService.GetTitle();
    }
}

Go back to LoginPage and set the BindingContext to new LoginViewModel. This makes a connection between the viewmodel and the view. Then hook up all the bindings by using SetBinding.

public class LoginPage : ContentPage
{
    public LoginPage()
    {
        BindingContext = new LoginViewModel(Navigation);

        var label = new Label();
        label.SetBinding(Label.TextProperty, new Binding("Header"));

        var button = new Button();
        button.SetBinding(Button.CommandProperty, new Binding("GoToMainCommand"));
        button.SetBinding(Button.TextProperty, new Binding("ButtonText"));

        var stackLayout = new StackLayout
        {
            HorizontalOptions = LayoutOptions.CenterAndExpand,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        stackLayout.Children.Add(label);
        stackLayout.Children.Add(button);

        Content = stackLayout;
    }
}

We also want to skin the app using Xamarin.Forms.Themes and Xamarin.Forms.Pages. Add Xamarin.Forms.Themes.Base, Xamarin.Forms.Themes.Light and Xamarin.Forms.Themes.Dark to all projects. Remember to check off pre release packages since Xamarin.Forms.Themes is still in preview. Xamarin.Forms.Pages will be added as a dependency to Xamarin.Forms.Themes.

Open up App.xaml and add this to ResourceDirectory.

<Application 
		xmlns="http://xamarin.com/schemas/2014/forms" 
		xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
		xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
		xmlns:light="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light"
		xmlns:local="clr-namespace:ConfDemo"
		x:Class="ConfDemo.App">
	<Application.Resources>
		<ResourceDictionary MergedWith="light:LightThemeResources" >
			<DataTemplate x:Key="SessionDetailTemplate">
				<local:SessionDetailPage Title="Foredrag" DataSource="{Binding Value}" Style="{StaticResource DetailPageStyle}" DefaultItemTemplate="{StaticResource DetailCell}" >
					<p:HeroImage Aspect="Fill" Text="{p:DataSourceBinding title}" Detail="{p:DataSourceBinding startTime}" ImageSource="{p:DataSourceBinding picture_absolute}" DataSource="{Binding Value}" />
				</local:SessionDetailPage>
			</DataTemplate>
		</ResourceDictionary>
	</Application.Resources>
</Application>

Here we are declaring a few new namespaces, light for Xamarin.Forms.Themes.Light and local for our own namespace and p for Xamarin.Forms.Pages. This is so that we can use that these namespaces when creating a DataTemplate for our Session detail page. The DataTemplate is added to the ResourceDictionary so that it is available throughout the app.

Next step is to add the mainpage that should host the list of sessions. Add a xaml forms page. Open up the xaml page and paste in the conference data within a ListDataPage (from Xamarin.Forms.Pages).

<p:ListDataPage 
		xmlns="http://xamarin.com/schemas/2014/forms" 
		xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
		xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
		StyleClass="Events"
         DetailTemplate="{StaticResource SessionDetailTemplate}" 
		x:Class="ConfDemo.SessionPage">
    <p:DataPage.DataSource>
        <p:JsonDataSource Source='[
					{
      "$id": "15",
      "id": 17,
      "title": "KEYNOTE: Towards the Open Source Economy",
      "hideTime": false,
      "startTime": "2014-10-28T14:00:00",
      "endTime": "2014-10-28T14:50:00",
      "abstract": "Open, collaborative development promises to revolutionize the way the economy operates by shifting the focus from profit-making proprietary production to meaning-making participatory production. Access to prior work and crowd-based contributions allow companies to innovate faster and a greater number of producers to foster a broader and more diverse ecosystem.",
      "description": "We also can (re)shape the artifacts we use and in this way shape our own experiences. What are the mechanisms by which this happens in practice – in our lives and in our work? What began a couple of decades ago as the open source movement is now extending into open source hardware, open product development, and open enterprise. How will these collaborative trends lead to a more efficient, satisfying and meaningful system of production? Do we have the courage to take the opportunity to disrupt manufacturing, stabilize economies, restore ecology, unleash productivity everywhere and leapfrog through old problems while leaving nobody behind?",
      "evalUrl": null,
      "conferenceId": 5,
      "roomId": 13,
"picture_absolute": "https://iconblobstorage.blob.core.windows.net/images/fbecc42e-02f4-48cc-883d-96754399a0ac.jpg",
},
    {
      "$id": "21",
      "id": 65,
      "title": "What every Eclipse developer should know about Eclipse 4 (E4)",
      "hideTime": false,
      "startTime": "2014-10-28T09:00:00",
      "endTime": "2014-10-28T12:00:00",
      "abstract": "This tutorial will give you a jumpstart on the new concepts of the Eclipse 4 Application Platform. If you have previous experience developing with RCP 3.x but limited or no experience with e4, this tutorial is designed for you. ",
      "description": "Using a sample RCP application, we introduce the most important features of the new platform, such as the Application Model, Dependency Injection and the new Programming Model. We complete the introduction with an overview of the most important services available, such as the selection or preference services. All topics include hands-on examples that we’ll work through together. Finally, we demonstrate how innovations from Eclipse 4 can be integrated into existing applications based on Eclipse 3.x and introduce possible migration paths.\r\nThis session is a revised submission of the EclipseCon North America tutorial, which received excellent feedback and was well attended. Part of the content is also available as a tutorial article series:",
      "evalUrl": null,
      "conferenceId": 5,
      "roomId": 12,
					      "picture_absolute": "https://iconblobstorage.blob.core.windows.net/images/f4a16b3a-7d4d-43e3-9901-4d89e5685803.jpg",
   
    },
    {
      "$id": "23",
      "id": 66,
      "title": "Lambdas and Streams:Functional Coding With Java SE 8",
      "hideTime": false,
      "startTime": "2014-10-28T09:00:00",
      "endTime": "2014-10-28T12:00:00",
      "abstract": "The big new features in Java SE 8 are the introduction of Lambda expressions to the language syntax and the Streams API in the standard class libraries. When combined these introduce a functional style of programming to Java for the first time. This tutorial will take developers who already know Java through these new features using the following structure:",
      "description": "Introduction:\r\nWhy does Java need Lambda expressions?\r\nWhat are the key differences between imperative and functional programming  \r\nLambda expression basics\r\nSyntax of Lambda expressions including method and constructor references\r\nStreams API basics\r\nWhat is a Stream and how do you use it\r\nFunctional interfaces\r\nStreams and Lambda expressions\r\nUse of Optionals with streams\r\nReal world streams usage\r\nVarious examples of the use of the streams API will be discussed to show how they are used in real code and how complex tasks can be written very succinctly.\r\nSome thoughts on the way you need to change your thinking in order to use streams effectively (use of infinite streams, etc).\r\nSupport for Lambdas and streams development with Eclipse\r\nConclusions\r\nWrap up and places to get more information.",
      "evalUrl": null,
      "conferenceId": 5,
      "roomId": 14,
	"picture_absolute": "https://iconblobstorage.blob.core.windows.net/images/0a1aed0c-ad4f-4847-9fc8-30ed73d4efab.jpg",
    }
  ]' /></p:DataPage.DataSource>
		<p:DataPage.DefaultItemTemplate>
		<DataTemplate>
		<TextCell Text="{Binding Value[title]}" Detail="{Binding Value[abstract]}"  />
		</DataTemplate>
	</p:DataPage.DefaultItemTemplate>
</p:ListDataPage>

Here I have copied over json data, but it is also possible to point to an url where you have your json data. I have used a built in style class “Events” but it is of course possible to create your own style class. For the DataTemplate we use the template we already have specified in App.xaml.

Now it is time to open up the MainPage.cs for the final touches.

public partial class MainPage : ListDataPage
{
    public MainPage()
    {
        InitializeComponent();
        Title = "Agenda";
    }
}

public class SessionDetailPage : DataPage
{
    public SessionDetailPage()
    {
        ((IDataSourceProvider)this).MaskKey("$id");
        ((IDataSourceProvider)this).MaskKey("id");
        ((IDataSourceProvider)this).MaskKey("hideTime");
        ((IDataSourceProvider)this).MaskKey("evalUrl");
        ((IDataSourceProvider)this).MaskKey("conferenceId");
        ((IDataSourceProvider)this).MaskKey("roomId");

        SetBinding(TitleProperty, new DataSourceBinding("title"));
    }
}

We are inheriting from a ListDataPage instead of a ContentPage, we are also setting up the DataPage for sessions. We can add MaskKey to the properties that we don’t want to show.

The app is now ready to go.
You can find this project as a GitHub repo.

Xamarin resources

Great articles
To stay updated
To reach out for help
Awesome guys making Xamarin better

goldnarms

Arnstein Johansen is a .NET Developer with a speciality in web development, but he also dabbles in mobile development and everything new and exciting. Arnstein works for Itema AS, a mid-size consultant agency in Trondheim. Itema has 25 consultants and recently won the prize for Norway's best workplace. He likes to share his knowledge by holding talks for others, either it is clients, colleagues or likeminded developers in user groups. He has hands-on experience from large projects, the latest from Urørt where he leads a team of developers creating a music service used by around 100000 users.

No Comments

Leave a reply