Moving my blog to a new home

It’s been a while since I posted on this blog! Not because I stopped blogging or caring about the community, but in the past year I focused my efforts on publishing new content and articles in the Tech Community website of my team at Microsoft.

Over time, I started to work on many different technologies. This blog started with Windows developer content, then I moved into the Microsoft 365 ecosystem, and I’ve started to share articles around building apps for Teams, add-ins for Microsoft 365 apps, etc.

Now, like many other colleagues, I’m supporting the AI motion in Microsoft, focusing mostly on Microsoft 365 and Copilot. To mark the occasion, I decided it was about time to reboot my blog and start sharing again my learnings using my own platform. As Scott Hanselman often shares, owning your content is the best way to make sure that it doesn’t disappear if your blogging platform of choice goes out of the market. As such, I decided to reboot my blog not only from a content perspective, but starting from scratch: new technology, new name.

Please welcome The Developer’s Cantina (yeah, I’m a big Star War fan)!

The new blog is based on Hugo, which is a static blogging platform hosted on Azure Static Web App. This means that my posts are simply made by Markdown files, which are stored on my hard disk. Whenever I want to publish a post, I simply commit a new Markdown file (and the related images, if I have them) into a GitHub repository. A GitHub Action generated by Azure does all the heavy work, by compiling the content of the repository into static web content (HTML, CSS and a little JavaScript), which is then served via HTTPS.

The choice of this platform gives me a few advantages:

  • Since the posts are simply Markdown files, I can store them anywhere. If at any point in time I should decide to move away from Azure Static Web App, I just need to change the GitHub Action to point to another platform.
  • If I need to recover my content, I don’t need to host a blog platform first to read it. I can just open the Markdown files with Visual Studio Code or any other editor.
  • There is no database or server-side code, everything is static and running on the client. As such, the blog is super-fast.

For the moment, this old blog will stay online, even if most of the content on is now outdated. I still haven’t made up my mind if migrating it to the new blog. Technically it’s doable, there’s a handy tool to convert content from WordPress to Hugo (or, for what matters, for almost any blogging platform), but I still need to evaluate if it makes sense from a “quality” perspective.

Thanks to everyone who visited my old blog so far, I hope I will see you in The Developer’s Cantina!

Posted in Developer's life | Leave a comment

Prism for Xamarin Forms – Handling platform specific code (Part 4)

Xamarin Forms is cool because it allows to share not just the business logic but also the user interface, unlike the traditional Xamarin approach, which requires to create multiple projects with its own user experience and features. However, at some point, even with Xamarin Forms you have to deal with platform specific code: unless your application leverages only plain and simple features that can be embedded into a PCL (like in the sample project we’ve created in the previous posts, where we simply downloaded some data from a REST API and we displayed it to the user), sooner or later you will have to use a feature that requires to write code which is different based on the target platform. There are many samples of this scenario: one of the most common is geo localization. Android, iOS and Windows offer a way to geo localize the user, but every platform uses its own approach and APIs, so you can’t include them in the Portable Class Library, since these APIs aren’t shared among the platform.

Luckily, to make the developer’s life easier, Xamarin has created many plugins for the most common scenarios, like geo localization, file system access, network, etc. which are available on NuGet or GitHub (https://github.com/xamarin/XamarinComponents)

However, not all the scenarios are covered, so it may easily happen that you are required to implement your own plugin. Xamarin Forms includes an infrastructure to handle this requirement in an easy way, based on a class called DependencyService. From a high level, here is how it works:

  1. In your PCL you create an interface, which describes the methods you want to use in your shared code (for example, you could create an interface called IGeolocatorService which offers a GetPosition() method to retrieve the current location of the user). However, since it’s an interface, it describes just the operations you want to perform, without actually implementing them.
  2. In every platform specific project, you create a class that implement this interface, using the actual APIs provided by the platform. This means that, for example, your Android project will contain an AndroidGeolocatorService, which will contain the actual implementation of the GetPosition() method using the Android APIs. These classes have to be decorated with a special attribute provided by Xamarin Forms called Dependency with, as parameter, a reference to the type of the class itself:
[assembly: Dependency(typeof(AndroidGeolocatorService))]
namespace InfoSeries.Droid.Services
{
    public class AndroidGeolocatorService: IGeolocatorService
    {
        public async Coordinates GetPosition()
        {
            //implementation using Android APIs
        }
    }
}

Thanks to this attribute, you are now able to use the DependencyService class and the Get<T>() method (where T is the interface type) in your PCL to get the proper implementation of the service, based on the platform where the app is running. Consequently, let’s say that in your PCL you have, at some point, the following code:

IGeolocatorService service = DependencyService.Get<IGeolocatorService>();
var result = service.GetPosition();

When the Xamarin Forms app is launched on an Android device, the Get<IGeolocatorService>() method will return an instance of the AndroidGeolocationService class; vice versa, if the app is launched on a Windows 10 device, the method will return an instance of the UwpGeolocationService class, which would have been created into the specific UWP project of the solution.

So far, so good. However, to reach this goal in our MVVM application, we would need to use the DependencyService class in a ViewModel, which isn’t a great approach: using a static property in a ViewModel makes things harder to test. Additionally, this approach would require us to use two different approaches based on the service type:

  1. If it’s a non platform specific service (like the TsApiService class we created in the previous posts to interact with the TrackSeries APIs), we register it into the Prism container and we let it automatically be injected into the ViewModel’s constructor.
  2. If it’s a platform specific service (like the previous AndroidGeolocatorService class), we have to access to it through the DependencyService class and not through the standard Prims container.

With other MVVM frameworks, a typical workaround is to use the DependencyService in the framework’s bootstrapper to get the platform specific instance and then register it into the dependency container we’re using. This way, we can continue to leverage the usual approach to simply add a parameter in the ViewModel’s constructor and to have its implementation automatically injected. This is made possible by the fact that basically all the dependency containers allow to register not only a generic type (which means that, in this case, the container will create a new instance of the class when it’s requested) but also to assign a specific implementation to an interface.

Here is a sample code of how it would work:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<NavigationPage>();
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<DetailPage>();
    Container.RegisterType<ITsApiService, TsApiService>();

    var geoService = DependencyService.Get<IGeolocationService>();
    Container.RegisterInstance<IGeolocationService>(geoService);

}

However, Prism is smarter than that and it’s automatically able to register into its container every class he finds in each platform specific project decorated with the Dependency attribute. You can find a real example in the InfoSeries app on my GitHub repository: https://github.com/qmatteoq/XamarinForms-Prism/tree/master/InfoSeries

I’ve decided to implement a feature that allows a user to share, from within the detail page of a TV Show, the poster image of the show. This is something that needs to be implemented in a different way for each platform (since each of them has its own unique APIs to share content) and we can’t leverage an existing plugin (since the one available in the Xamarin repository supports only text sharing). As such, I’ve created in the Xamarin Forms Portable Class Library the following interface:

public interface IShareService
{
    Task SharePoster(string title, string image);
}

The interface simply describes an asynchronous method, called ShareShirt(), which accepts as parameter the title of the show and the path of the image to share. The next step is to implement this interface in every platform specific project. I won’t go into the details, because it would be out of scope for the post but, for example, here is how it looks the implementation in the Android project:

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using InfoSeries.Droid.Services;
using InfoSeries.Services;
using Xamarin.Forms;
using Environment = Android.OS.Environment;

[assembly: Dependency(typeof(AndroidShareService))]
namespace InfoSeries.Droid.Services
{
    public class AndroidShareService: IShareService
    {
        public async Task SharePoster(string title, string image)
        {
            var intent = new Intent(Intent.ActionSend);
            intent.SetType("image/png");
            Guid guid = Guid.NewGuid();
            var path = Environment.GetExternalStoragePublicDirectory(Environment.DataDirectory
                                                                + Java.IO.File.Separator + guid + ".png");

            HttpClient client = new HttpClient();
            var httpResponse = await client.GetAsync(image);
            byte[] imageBuffer = await httpResponse.Content.ReadAsByteArrayAsync();

            if (File.Exists(path.AbsolutePath))
            {
                File.Delete(path.AbsolutePath);
            }

            using (var os = new System.IO.FileStream(path.AbsolutePath, System.IO.FileMode.Create))
            {
                await os.WriteAsync(imageBuffer, 0, imageBuffer.Length);
            }

            intent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(path));

            var intentChooser = Intent.CreateChooser(intent, "Share via");

            Activity activity = Forms.Context as Activity;
            activity.StartActivityForResult(intentChooser, 100);
        }
    }
}

As you can see, the class implements the ShareShirt() method by downloading the poster image in the local storage of the app and then, by using specific Android APIs (like Activity or Intent), it starts the sharing operation. As you can see, the class is decorated with the Dependency attribute with, as parameter, the type of the class itself.

Thanks to Prism, that’s all we need to do. Now simply add, in the DetailPageViewModel, a parameter of type IShareService in the class constructor, so that you can use it the command that will be invoked when the user will press the button to share the image. Here is how our updated DetailPageViewModel looks like:

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private readonly IShareService _shareService;
    private SerieFollowersVM _selectedShow;

    public SerieFollowersVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }

    public DetailPageViewModel(IShareService shareService)
    {
        _shareService = shareService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public void OnNavigatedTo(NavigationParameters parameters)
    {
        SelectedShow = parameters["show"] as SerieFollowersVM;
    }

    private DelegateCommand _shareItemCommand;

    public DelegateCommand ShareItemCommand
    {
        get
        {
            if (_shareItemCommand == null)
            {
                _shareItemCommand = new DelegateCommand(async () =>
                {
                    string image = SelectedShow.Images.Poster;
                    await _shareService.SharePoster(SelectedShow.Name, image);
                });
            }

            return _shareItemCommand;
        }
    }
}

We have added an IShareService parameter in the constructor and we have defined a DelegateCommand called ShareItemCommand: when it’s invoked, it will simply call the ShareShirt() method exposed by the IShareService interface, passing as parameter the name of the show and the URL of the poster image (which can be both retrieved from the SelectedShow property).

In the end, in the DetailPage.xaml we have added a ToolbarItem control, which adds a new button in the UI’s toolbar (which is rendered in a different way based on the platform, for example on UWP it’s rendered as a button in the CommandBar):

<ContentPage.ToolbarItems>
  <ToolbarItem Text="Share" Command="{Binding Path=ShareItemCommand}" Order="Secondary"/>
</ContentPage.ToolbarItems>
Screenshot_2016-08-22-14-46-47 Screenshot_2016-08-22-14-46-38

 

Nothing special here: the control has a text and it’s connected through binding to the ShareItemCommand we have previously defined in the ViewModel. Now launch the application on an Android device or emulator, choose one TV Show and use the new share option we’ve just added: automagically, Android will show us the share chooser, which will allow the user to choose which target application will receive the image. As you can see, we didn’t have to register anything related to the IShareService in the App class: Prism did everything on its own. Of course, if we want to achieve the same result also when the app is running on iOS or on Windows 10, we need to create also an implementation of the IShareService interface in the other platform specific projects.

Pretty cool, isn’t it?

Wrapping up

We have concluded our journey in learning how the most recent version of the Prism framework has been greatly improved, specifically when it comes to support Xamarin Forms. Thanks to Prism and Xamarin, it will be much easier to create great cross platform application using the MVVM pattern and leveraging the same skills you have learned as a developer by creating WPF, Silverlight, Windows Store or UWP apps. As a final reminder, don’t forger that all the samples used in this series of posts are available on my GitHub account: https://github.com/qmatteoq/XamarinForms-Prism

Happy coding!

Posted in Xamarin | Tagged , , , | 5 Comments

Prism for Xamarin Forms – Advanced navigation (Part 3)

In the previous post, we’ve expanded a bit our original sample application, by creating a service to interact with the APIs offered by the TrackSeries website, by using it to populate some data in the app and, in the end, by creating a detail page where to see more info about the selected show. This way, we have understood how Prism allows to manage some basic concepts like navigation, page’s lifecycle and dependency injection.

In this post we’re going to see a couple of more advanced concepts which, however, can be fundamental when it comes to develop a real project using Xamarin Forms.

Advanced navigation

If you have tested the previous version of the app, you would have noted some issues with navigation, especially if you have navigated to the detail page of a TV Show. For example, if you test the UWP version on a Windows 10 PC, you will notice that the Back button that is usually available in the top left corner of the chrome of the windows is missing. Or on Android or iOS, the navigation bar which shows the title of the page and the virtual back button is missing, so if your device doesn’t have an actual back button (like an iPhone), you don’t have a way to go back to the home once you are into a show detail page.

Screenshot_2016-08-20-22-51-58

If you have some previous experience with Xamarin Forms you should already have an idea why this problem is happening. Every basic page in a Xamarin Forms app is represented by the ContentPage class, but it can be embedded in other kind of pages to provide more advanced navigation scenarios, like a NavigationPage (to provide a navigation UI) or a TabbedPage (to show multiple pages in different tabs). In the sample we’ve created so far, we’ve just created two basic pages (of type ContentPage) and then we’ve simply navigated to them using the NavigationService. We haven’t specified anywhere that the pages should have been actually embedded into a NavigationPage to get access to the navigation UI.

To achieve this goal in a plain Xamarin Forms app, we would have done something like this:

public partial class App : Application
{
    public App()
    {
        MainPage = new NavigationPage(new MainPage());
    }     
}

An instance of the MainPage of the application is embedded into a new instance of a NavigationPage: from now on, the NavigationPage will be the container of each ContentPage that the user will see, providing a consistent navigation UI across every page of the app. However, with the Prism approach, we can’t recreate the same approach:

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>();
        Container.RegisterTypeForNavigation<DetailPage>();
        Container.RegisterType<ITsApiService, TsApiService>();
    }
}

We have just registered, in the Container, the MainPage and then we have called the NavigateAsync() method of the NavigationService, which accepts only the key that identifies the destination page: we can’t specify, in any way, that this page should be embedded into a NavigationPage.

Luckily, Prism has a smart solution for this problem: deep linking. One of the features offered by Prism for Xamarin Forms, in fact, is to support complex queries as parameters of the NavigateAsync() method. For example, we can specify queries like “MainPage/DetailPage?id=1” to navigate directly to the detail page of the app and, at the same time, passing a parameter called id with value 1. This approach is very useful when, for example, you want to link a specific page of your application from another application, a website or a section of your app.

We can leverage this feature also to achieve the goal of embedding our pages into a NavigationPage: first, we need to register the base NavigationPage type included in Xamarin Forms as a type for navigation in the Container. Then, we can use the query “NavigationPage/MainPage” to tell to the NavigationService that we need to navigate first to the page identified by the NavigationPage key and then to the one identified by the MainPage key. Since the NavigationPage isn’t actually a real page, but just a container, the end result will be the same we’ve seen in the first sample code: the MainPage (and every consequent page in the navigation flow) will be embedded into a NavigationPage.

Here is how our new App class looks like:

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("NavigationPage/MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<NavigationPage>();
        Container.RegisterTypeForNavigation<MainPage>();
        Container.RegisterTypeForNavigation<DetailPage>();
        Container.RegisterType<ITsApiService, TsApiService>();
    }
}

 

Thanks to this change, now we have a proper navigation bar, as you can see in the following screenshot taken from the Android version:

Screenshot_2016-08-20-22-53-06

Another example of complex deep linking is using query parameters. You can use a navigation query like the following one:

NavigationService.NavigateAsync("FirstPage?id=1&title=First page");

Automatically, the destination page will receive, in the NavigationParams object of the OnNavigatedTo() method, two items: one with key id and value 1 and one with key title and value First page.

public void OnNavigatedTo(NavigationParameters parameters)
{
    string id = parameters["id"].ToString();
    string title = parameters["title"].ToString();

    Title = $"Page with id {id} and title {title}";
}

Eventually, you can use this feature to leverage even more complex navigation flows, which involves container for multiple pages.

Let’s try to better understand this scenario with a real example. We have already talked about the concept that Xamarin Forms offers some pages which doesn’t display any actual content, but that they act as a container for other pages. We’ve already seen an example of this concept: the NavigationPage type doesn’t display any actual content, but it’s a container to add navigation UI and features to a ContentPage. Another similar container is TabbedPage, where every children page is displayed in a different tab.

Let’s say that we want to improve our TV show application and add two sections to the main page, using a TabbedPage control: the first section will display the list of upcoming shows, so it will be a simple ContentPage; the second section, instead, will display a list of the available TV Shows and, as such, it will be embedded into a NavigationPage, because we want to provide the ability to tap on a show and see more info about the selected show.

This is how our project would look like:

prism4

The application has two main sections (UpcomingShowsPage and ShowsListPage) and a detail page (DetailPage), each of them with its own ViewModel. The main pages are presented to the user as two sections of a tab control, which is defined in the MainTabbedPage.xaml file:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
            xmlns:views="clr-namespace:PrismTest.Views;assembly=PrismTest"
            prism:ViewModelLocator.AutowireViewModel="True"
            Title="Main page"
            x:Class="PrismTest.Views.MainTabbedPage">

  <views:UpcomingShowsPage />
  <NavigationPage Title="Shows list">
    <x:Arguments>
      <views:ShowsListPage />
    </x:Arguments>
  </NavigationPage>

</TabbedPage>

The UpcomingShowsPage is a simple ContentPage, while the ShowsListPsage is embedded into a NavigationPage, since the user has the chance to move to the DetailPage to see more info about the selected TV show. Now let’s say that, as a consequence of an user action, we want to redirect the user to the detail page of a specific TV Show.  With standard Xamarin Forms it wouldn’t a hard task to accomplish, but the real challenge would be to retain the whole navigation stack: we want to bring the user to the detail page, but we also want that, when he presses the back button, he follows the proper backward navigation flow (so DetailPage –> ShowListPage). Additionally, everything should be done by keeping the focus in the second tab, since ShowListPage is part of a TabbedPage.

Sounds complicated, isn’t it? Well, here is how it’s easy to achieve this goal with Prism:

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MainTabbedPage/NavigationPage/ShowsListPage/DetailPage?id=1");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<UpcomingShowsPage>();
        Container.RegisterTypeForNavigation<ShowsListPage>();
        Container.RegisterTypeForNavigation<DetailPage>();
        Container.RegisterTypeForNavigation<MainTabbedPage>();
        Container.RegisterTypeForNavigation<NavigationPage>();
    }
}

As usual, in the RegisterTypes() method, we have registered every page that compose our application. Then, we invoke the NavigateAsync() method of the NavigationService passing the whole path we want to follow: MainTabbedPage/NavigationPage/ShowsListPage/DetailPage with an additional parameter that identifies the selected TV Show, that we can intercept in the OnNavigatedTo() method of the DetailPageViewModel.

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private readonly ITsApiService _tsApiService;
    private SerieInfoVM _selectedShow;

    public SerieInfoVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }

    public DetailPageViewModel(ITsApiService tsApiService)
    {
        _tsApiService = tsApiService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        int id = Convert.ToInt32(parameters["id"]);
        SelectedShow = await _tsApiService.GetSerieById(id);
    }
}

Thanks to Prism, other than achieving the goal of redirecting the user directly to the page we’re interested into, we have also retained the full backward navigation stack. The following images show you what happens when you press the Back button:

Screenshot_2016-08-22-11-40-17 Screenshot_2016-08-22-11-42-41

As you can see, from the detail page of the show (the screenshot on the left) we’ve been properly redirected to the previous page in the stack (the shows list, displayed in the screenshot on the right), even if we didn’t actually visited it during our navigation flow (since the app was directly loaded in the detail page). Additionally, we’ve kept the focus on the second tab (Shows list) so the user has still the chance, at any time, to move to the first one (Upcoming shows). Pretty cool, isn’t it?

Attention: in the current Prism implementation dealing with the TabbedPage control has a downside. In our example, as we’ve seen from the screenshot of the project’s structure, the Upcoming Shows section is represented by a standard page (UpcomingShowsPage) with its own ViewModel (UpcomingShowsPageViewModel), which implements the INavigationAware interface with the goal to leverage the OnNavigatedTo() method to load the data (in our case, the list of upcoming shows). As such, the UpcomingShowsPageViewModel would look like this:

public class UpcomingShowsPageViewModel : BindableBase, INavigationAware
{
    private readonly ITsApiService _tsApiService;

    private ObservableCollection<SerieFollowersVM> _topSeries;

    public ObservableCollection<SerieFollowersVM> TopSeries
    {
        get { return _topSeries; }
        set { SetProperty(ref _topSeries, value); }
    }

    public UpcomingShowsPageViewModel(ITsApiService tsApiService)
    {
        _tsApiService = tsApiService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        var series = await _tsApiService.GetStatsTopSeries();
        TopSeries = new ObservableCollection<SerieFollowersVM>(series);
    }
}

However, if you tap on the Upcoming Shows tab you’ll notice that nothing won’t happen and the OnNavigatedTo() method won’t be triggered. The reason is that the navigation methods implemented by the INavigationAware interface are raised only when you navigate using the Prism NavigationService. If the navigation happens without leveraging it (like, in this case, where the navigation to the other tab is handled directly by the Xamarin Forms infrastructure), the OnNavigatedTo() method in the ViewModel will never be invoked and, as such, our data will never be loaded. There’s a solution in the works, which involves using a behavior, but it hasn’t been included yet in the current Prism version. You can follow the discussion and the proposed solution on GitHub: https://github.com/PrismLibrary/Prism/issues/650

Wrapping up

In this post we’ve learned how to leverage the deep linking featured offered by Prism, which allows to handle complex navigation patterns in an easy way, keeping at the same time the proper backward navigation path. In the next post (which will be the last one), we’ll see instead how to use platform specific code in a Xamarin Forms application created with Prism. You can find all the samples on my GitHub repository: the InfoSeries one (https://github.com/qmatteoq/XamarinForms-Prism/tree/master/InfoSeries) shows you the first approach (simple navigation using a NavigationPage), the DeepNavigation one (https://github.com/qmatteoq/XamarinForms-Prism/tree/master/DeepNavigation) instead shows you the advanced deep link feature we’ve seen in the second part of the post. Happy coding!

Posted in Xamarin | Tagged , , , | 1 Comment

Prism for Xamarin Forms – Basic navigation and dependency injection (Part 2)

In the previous post we’ve started to see the basic concepts on how to leverage the new version of Prism (6.2) to implement the MVVM pattern in a Xamarin Forms app. So far, we haven’t seen nothing special that we couldn’t do also with another framework: we have just created a View, a ViewModel and we connected them through binding. In this post, we’re going to see how Prism can be helpful to handle a very common scenario which can be hard to handle in a MVVM app: navigation and page’s lifecycle.

As we’ve mentioned in the previous post, we’re going to create a simple client for TrackSeries, a website which offers many information about TV Shows. The app will display the current top series and will allow the user to discover more about them. To achieve this goal, we can use a set of REST services provided by the website, which are very simple to use and which follow the standard best practices of dealing with REST services: you invoke a URL using a HTTP command and you receive back a JSON response with the result.

For example, if you want to know which are the top series at the moment, you can just perform a HTTP GET request to the following URL: https://api.trackseries.tv/v1/Stats/TopSeries The service will return you a JSON response with all the details about the top series:

[
   {
      "id":121361,
      "name":"Game of Thrones",
      "followers":10230,
      "firstAired":"2011-04-17T21:00:00-04:00",
      "country":"us",
      "overview":"Seven noble families fight for control of the mythical land of Westeros. Friction between the houses leads to full-scale war. All while a very ancient evil awakens in the farthest north. Amidst the war, a neglected military order of misfits, the Night's Watch, is all that stands between the realms of men and the icy horrors beyond.",
      "runtime":55,
      "status":"Continuing",
      "network":"HBO",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt0944947",
      "tvdbId":121361,
      "tmdbId":1399,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/121361-49.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/121361-15.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/121361-g22.jpg"
      },
      "genres":[
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":5,
            "name":"Fantasy"
         }
      ],
      "added":"2014-08-08T13:30:46.227",
      "lastUpdated":"2016-08-18T03:03:50.05",
      "followedByUser":false,
      "slugName":"game-of-thrones"
   },
   {
      "id":257655,
      "name":"Arrow",
      "followers":7517,
      "firstAired":"2012-10-10T20:00:00-04:00",
      "country":"us",
      "overview":"Oliver Queen and his father are lost at sea when their luxury yacht sinks. His father doesn't survive. Oliver survives on an uncharted island for five years learning to fight, but also learning about his father's corruption and unscrupulous business dealings. He returns to civilization a changed man, determined to put things right. He disguises himself with the hood of one of his mysterious island mentors, arms himself with a bow and sets about hunting down the men and women who have corrupted his city.",
      "runtime":45,
      "status":"Continuing",
      "network":"The CW",
      "airDay":"Wednesday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt2193021",
      "tvdbId":257655,
      "tmdbId":1412,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/257655-8.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/257655-47.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/257655-g9.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         }
      ],
      "added":"2014-08-08T13:37:00.133",
      "lastUpdated":"2016-08-15T03:11:32.013",
      "followedByUser":false,
      "slugName":"arrow"
   },
   {
      "id":153021,
      "name":"The Walking Dead",
      "followers":7185,
      "firstAired":"2010-10-31T21:00:00-04:00",
      "country":"us",
      "overview":"The world we knew is gone. An epidemic of apocalyptic proportions has swept the globe causing the dead to rise and feed on the living. In a matter of months society has crumbled. In a world ruled by the dead, we are forced to finally start living. Based on a comic book series of the same name by Robert Kirkman, this AMC project focuses on the world after a zombie apocalypse. The series follows a police officer, Rick Grimes, who wakes up from a coma to find the world ravaged with zombies. Looking for his family, he and a group of survivors attempt to battle against the zombies in order to stay alive.\n",
      "runtime":50,
      "status":"Continuing",
      "network":"AMC",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt1520211",
      "tvdbId":153021,
      "tmdbId":1402,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/153021-38.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/153021-77.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/153021-g44.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":6,
            "name":"Horror"
         },
         {
            "id":20,
            "name":"Suspense"
         }
      ],
      "added":"2014-08-08T13:31:18.617",
      "lastUpdated":"2016-08-18T03:04:00.28",
      "followedByUser":false,
      "slugName":"the-walking-dead"
   },
   {
      "id":279121,
      "name":"The Flash (2014)",
      "followers":7069,
      "firstAired":"2014-10-07T20:00:00-04:00",
      "country":"us",
      "overview":"After a particle accelerator causes a freak storm, CSI Investigator Barry Allen is struck by lightning and falls into a coma. Months later he awakens with the power of super speed, granting him the ability to move through Central City like an unseen guardian angel. Though initially excited by his newfound powers, Barry is shocked to discover he is not the only \"meta-human\" who was created in the wake of the accelerator explosion – and not everyone is using their new powers for good. Barry partners with S.T.A.R. Labs and dedicates his life to protect the innocent. For now, only a few close friends and associates know that Barry is literally the fastest man alive, but it won't be long before the world learns what Barry Allen has become... The Flash.",
      "runtime":45,
      "status":"Continuing",
      "network":"The CW",
      "airDay":"Tuesday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt3107288",
      "tvdbId":279121,
      "tmdbId":60735,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/279121-37.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/279121-23.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/279121-g7.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         }
      ],
      "added":"2014-08-08T13:45:59.087",
      "lastUpdated":"2016-08-17T03:09:18.7",
      "followedByUser":false,
      "slugName":"the-flash-2014"
   },
   {
      "id":80379,
      "name":"The Big Bang Theory",
      "followers":6922,
      "firstAired":"2007-09-25T20:00:00-04:00",
      "country":"us",
      "overview":"What happens when hyperintelligent roommates Sheldon and Leonard meet Penny, a free-spirited beauty moving in next door, and realize they know next to nothing about life outside of the lab. Rounding out the crew are the smarmy Wolowitz, who thinks he's as sexy as he is brainy, and Koothrappali, who suffers from an inability to speak in the presence of a woman.",
      "runtime":25,
      "status":"Continuing",
      "network":"CBS",
      "airDay":"Monday",
      "airTime":"8:00 PM",
      "contentRating":"TV-PG",
      "imdbId":"tt0898266",
      "tvdbId":80379,
      "tmdbId":1418,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/80379-43.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/80379-38.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/80379-g28.jpg"
      },
      "genres":[
         {
            "id":3,
            "name":"Comedy"
         }
      ],
      "added":"2014-08-08T13:27:13.18",
      "lastUpdated":"2016-08-18T03:03:10.947",
      "followedByUser":false,
      "slugName":"the-big-bang-theory"
   },
   {
      "id":176941,
      "name":"Sherlock",
      "followers":6387,
      "firstAired":"2010-07-25T20:30:00+01:00",
      "country":"gb",
      "overview":"Sherlock is a British television crime drama that presents a contemporary adaptation of Sir Arthur Conan Doyle's Sherlock Holmes detective stories. Created by Steven Moffat and Mark Gatiss, it stars Benedict Cumberbatch as Sherlock Holmes and Martin Freeman as Doctor John Watson.",
      "runtime":90,
      "status":"Continuing",
      "network":"BBC One",
      "airDay":"Sunday",
      "airTime":"8:30 PM",
      "contentRating":"TV-14",
      "imdbId":"tt1475582",
      "tvdbId":176941,
      "tmdbId":19885,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/176941-11.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/176941-3.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/176941-g5.jpg"
      },
      "genres":[
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":16,
            "name":"Mystery"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:32:27.247",
      "lastUpdated":"2016-08-17T03:07:09.747",
      "followedByUser":false,
      "slugName":"sherlock"
   },
   {
      "id":263365,
      "name":"Marvel's Agents of S.H.I.E.L.D.",
      "followers":5372,
      "firstAired":"2013-09-24T22:00:00-04:00",
      "country":"us",
      "overview":"Phil Coulson (Clark Gregg, reprising his role from \"The Avengers\" and \"Iron Man\" ) heads an elite team of fellow agents with the worldwide law-enforcement organization known as SHIELD (Strategic Homeland Intervention Enforcement and Logistics Division), as they investigate strange occurrences around the globe. Its members -- each of whom brings a specialty to the group -- work with Coulson to protect those who cannot protect themselves from extraordinary and inconceivable threats, including a formidable group known as Hydra.",
      "runtime":45,
      "status":"Continuing",
      "network":"ABC (US)",
      "airDay":"Tuesday",
      "airTime":"10:00 PM",
      "contentRating":"TV-PG",
      "imdbId":"tt2364582",
      "tvdbId":263365,
      "tmdbId":1403,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/263365-16.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/263365-26.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/263365-g7.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":2,
            "name":"Adventure"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":5,
            "name":"Fantasy"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         }
      ],
      "added":"2014-08-08T13:39:45.967",
      "lastUpdated":"2016-08-18T03:05:30.987",
      "followedByUser":false,
      "slugName":"marvels-agents-of-shield"
   },
   {
      "id":81189,
      "name":"Breaking Bad",
      "followers":5227,
      "firstAired":"2008-01-20T21:00:00-04:00",
      "country":"us",
      "overview":"Walter White, a struggling high school chemistry teacher, is diagnosed with advanced lung cancer. He turns to a life of crime, producing and selling methamphetamine accompanied by a former student, Jesse Pinkman, with the aim of securing his family's financial future before he dies.",
      "runtime":45,
      "status":"Ended",
      "network":"AMC",
      "airDay":"Sunday",
      "airTime":"9:00 PM",
      "contentRating":"TV-MA",
      "imdbId":"tt0903747",
      "tvdbId":81189,
      "tmdbId":1396,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/81189-10.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/81189-21.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/81189-g21.jpg"
      },
      "genres":[
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":20,
            "name":"Suspense"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:27:33.917",
      "lastUpdated":"2016-08-13T03:01:47.063",
      "followedByUser":false,
      "slugName":"breaking-bad"
   },
   {
      "id":247808,
      "name":"Suits",
      "followers":4835,
      "firstAired":"2011-06-24T21:00:00-04:00",
      "country":"us",
      "overview":"Suits follows college drop-out Mike Ross, who accidentally lands a job with one of New York's best legal closers, Harvey Specter. They soon become a winning team with Mike's raw talent and photographic memory, and Mike soon reminds Harvey of why he went into the field of law in the first place.",
      "runtime":45,
      "status":"Continuing",
      "network":"USA Network",
      "airDay":"Wednesday",
      "airTime":"9:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt1632701",
      "tvdbId":247808,
      "tmdbId":37680,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/247808-27.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/247808-43.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/247808-g17.jpg"
      },
      "genres":[
         {
            "id":4,
            "name":"Drama"
         }
      ],
      "added":"2014-08-08T13:33:45.423",
      "lastUpdated":"2016-08-18T03:04:21.37",
      "followedByUser":false,
      "slugName":"suits"
   },
   {
      "id":274431,
      "name":"Gotham",
      "followers":4718,
      "firstAired":"2014-09-23T20:00:00-04:00",
      "country":"us",
      "overview":"An action-drama series following rookie detective James Gordon as he battles villains and corruption in pre-Batman Gotham City.",
      "runtime":45,
      "status":"Continuing",
      "network":"FOX (US)",
      "airDay":"Monday",
      "airTime":"8:00 PM",
      "contentRating":"TV-14",
      "imdbId":"tt3749900",
      "tvdbId":274431,
      "tmdbId":60708,
      "language":"en",
      "images":{
         "poster":"http://static.trackseries.tv/banners/posters/274431-17.jpg",
         "fanart":"http://static.trackseries.tv/banners/fanart/original/274431-22.jpg",
         "banner":"http://static.trackseries.tv/banners/graphical/274431-g6.jpg"
      },
      "genres":[
         {
            "id":1,
            "name":"Action"
         },
         {
            "id":4,
            "name":"Drama"
         },
         {
            "id":8,
            "name":"Science-Fiction"
         },
         {
            "id":14,
            "name":"Crime"
         },
         {
            "id":21,
            "name":"Thriller"
         }
      ],
      "added":"2014-08-08T13:44:55.4",
      "lastUpdated":"2016-08-17T03:08:55.473",
      "followedByUser":false,
      "slugName":"gotham"
   }
]

To use these APIs in the application, I’ve created a class called TsApiService with a set of methods that, by using the HttpClient class of the .NET Framework and the popular JSON.NET library, takes care of downloading the JSON, parsing it and returning a set of objects that can be easily manipulated using C#. To structure my solution in a better way, I’ve decided to place all the classes related to the communication with the REST APIs (like services and entities) in another Portable Class Library, called InfoSeries.Core, which is a different PCL than the one that hosts the real Xamarin Forms app.

Here is, for example, how the method that takes care of parsing the previous JSON and to return a list of C# objects looks like:

public async Task<List<SerieFollowersVM>> GetStatsTopSeries()
{
    using (HttpClient client = new HttpClient())
    {
        try
        {
            var response = await client.GetAsync("https://api.trackseries.tv/v1/Stats/TopSeries");
            if (!response.IsSuccessStatusCode)
            {
                var error = await response.Content.ReadAsAsync<TrackSeriesApiError>();
                var message = error != null ? error.Message : "";
                throw new TrackSeriesApiException(message, response.StatusCode);
            }
            return await response.Content.ReadAsAsync<List<SerieFollowersVM>>();
        }
        catch (HttpRequestException ex)
        {
            throw new TrackSeriesApiException("", false, ex);
        }
        catch (UnsupportedMediaTypeException ex)
        {
            throw new TrackSeriesApiException("", false, ex);
        }
    }
}

The GetAsync() method of the HttpClient class performs a GET request to the URL, returning as result the string containing the JSON response. This result is stored into the Content property of the response: in case the request is successful (we use the IsSuccessStatusCode property to check this condition), we use the ReadAsAsync<T> method exposed by the Content property to automatically convert the JSON result in a collection of SerieFollowersVM object. SerieFollowersVM is nothing else than a class that maps each property of the JSON response (like name, country or runtime) into a C# property:

public class SerieFollowersVM
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Followers { get; set; }
    public DateTimeOffset FirstAired { get; set; }
    public string Country { get; set; }
    public string Overview { get; set; }
    public int Runtime { get; set; }
    public string Status { get; set; }
    public string Network { get; set; }
    public DayOfWeek? AirDay { get; set; }
    public string AirTime { get; set; }
    public string ContentRating { get; set; }
    public string ImdbId { get; set; }
    public int TvdbId { get; set; }
    public string Language { get; set; }
    public ImagesSerieVM Images { get; set; }
    public ICollection<GenreVM> Genres { get; set; }
    public DateTime Added { get; set; }
    public DateTime LastUpdated { get; set; }
    public string SlugName { get; set; }
}

In the full sample on GitHub you’ll find many classes like this (which maps the various JSON responses returned by the TrackSeries APIs). Additionally, the TsApiService will implement additional methods, one for each API we want to leverage in our application. I won’t explain in details each method, since it would be out of scope for the article: you can see all the details on GitHub. For the purpose of this post, you just need to know that the service simply exposes a set of methods that we can use in the various ViewModels to retrieve info about the available TV Shows.

Note: by default, the HttpClient class doesn’t offer a ReadAsAsync<T> method, which is able to automatically deserialize the JSON response into C# objects. To get access to this extension method, we need to add the Microsoft.AspNet.WebApi.Client NuGet package to our Portable Class Library. To get it properly working, you need to add this package to every project of the solution (the Xamarin Forms PCL, the Core PCL and all the platform specific projects).

To properly leverage dependency injection, however, we need an interface that describes the operations offered by the TsApiService class. Here is how our interface looks like:

public interface ITsApiService
{
    Task<List<SerieFollowersVM>> GetStatsTopSeries();
    Task<SerieVM> GetSerieByIdAll(int id);
    Task<SerieInfoVM> GetSerieById(int id);
    Task<List<SerieSearch>> GetSeriesSearch(string name);
    Task<SerieFollowersVM> GetStatsSerieHighlighted();
}

Now that we have a service, we can learn how, thanks to Prism, we can register it into its dependency container and have it automatically injected in our ViewModels. Actually, from this point of view, there’s nothing special to highlight: the approach is the same we would use with any other MVVM framework which leverages a dependency injection approach. First, we need to register the association between the interface and the implementation we want to use in the container. In case of Prism, we need to do it in the RegisterTypes() method of the App class, by using the Container object and the RegisterType<T, Y>() method (where T is the interface and Y is the concrete implementation):

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterType<ITsApiService, TsApiService>();
}

Now, since both the MainPage and the TsApiService are registered in the container, we can get access to it in our ViewModel, by simply adding a parameter in the public constructor, like in the following sample:

public class MainPageViewModel : BindableBase
{
    private readonly ITsApiService _apiService;

    public MainPageViewModel(ITsApiService apiService)
    {
        _apiService = apiService;
    }
}

When the MainPageViewModel class will be loaded, the implementation of the ITsApiService we’ve registered in the container (in our case, the TsApiService class) will be automatically injected into the parameter in the constructor, allowing us to use it in all the other methods and properties we’re going to create in the ViewModel. With this approach, it will be easy for us to change the implementation of the service in case we need it: it will be enough to change the registered type in the App class and, automatically, every ViewModel will start to use the new version.

Handle the navigation’s lifecycle

Now that we have a service that offers a method to retrieve the list of the top series, we need to call it when the ViewModel is loaded: our goal is to display, in the main page of the app, a list of the most trending TV shows. However, we are about to face a common problem when it comes to use the MVVM pattern: the method to retrieve the list of top series is asynchronous but, with the current implementation, the only place where we can perform the data loading is the ViewModel’s constructor, which can’t execute asynchronous calls (in C#, in fact, the constructor of a class can’t be marked with the async keyword and, consequently, you can’t use the await prefix with a method). In a non-MVVM application, this problem would be easy to solve, thanks to the navigation’s lifecycle methods offered basically by every platform. Xamarin Forms makes no exception and we could leverage, in the code behind class of a XAML page, the methods OnAppearing() and OnDisappearing(): since they are events, we can call asynchronous code without issues.

To solve this problem, Prism offers an interface that we can implement in our ViewModels called INavigationAware: when we implement it, we have access to the OnNavigatedTo() and OnNavigatedFrom() events, which we can use to perform data loading or cleanup operations. Here is our MainPageViewModel looks like after implementing this interface:

public class MainPageViewModel : BindableBase, INavigationAware
{
    private readonly TsApiService _apiService;
    private ObservableCollection<SerieFollowersVM> _topSeries;

    public ObservableCollection<SerieFollowersVM> TopSeries
    {
        get { return _topSeries; }
        set { SetProperty(ref _topSeries, value); }
    }

    public MainPageViewModel(TsApiService apiService)
    {
        _apiService = apiService;
    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {

    }

    public async void OnNavigatedTo(NavigationParameters parameters)
    {
        var result = await _apiService.GetStatsTopSeries();
        TopSeries = new ObservableCollection<SerieFollowersVM>(result);
    }
}

As you can see, now we have implemented a method called OnNavigatedTo(), where we can safely execute our asynchronous calls and load the data: we call the GetStatsTopSeries() method of the TsApiService class and we encapsulate the resulting collection into an ObservableCollection property. This is the property we’re going to connect, through binding, to a ListView control, in order to display the list of TV Shows in the main page.

For completeness, here is how the XAML of the MainPage looks like:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="Info Series">
  
  <ContentPage.Resources>
    <ResourceDictionary>
      <DataTemplate x:Key="TopSeriesTemplate">
        <ViewCell>
          <ViewCell.View>
            <Grid>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="2*" />
              </Grid.ColumnDefinitions>

              <Image Source="{Binding Images.Poster}" Grid.Column="0" x:Name="TopImage" />
              <StackLayout Grid.Column="1" Margin="12, 0, 0, 0" VerticalOptions="Start">
                <Label Text="{Binding Name}" FontSize="18" TextColor="#58666e" FontAttributes="Bold" />
                <StackLayout Orientation="Horizontal">
                  <Label Text="Runtime: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Runtime}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Air day: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding AirDay}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Country: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Country}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
                <StackLayout Orientation="Horizontal">
                  <Label Text="Network: " FontSize="14" TextColor="#58666e" />
                  <Label Text="{Binding Network}" FontSize="14" TextColor="#98a6ad" Margin="5, 0, 0, 0" />
                </StackLayout>
              </StackLayout>
            </Grid>
          </ViewCell.View>
        </ViewCell>


      </DataTemplate>
    </ResourceDictionary>
  </ContentPage.Resources>

  <ListView ItemTemplate="{StaticResource TopSeriesTemplate}"
            ItemsSource="{Binding Path=TopSeries}" RowHeight="200"/>
  
</ContentPage>

If you already know Xamarin Forms (or XAML in general), you should find this code easy to understand: the page contains a ListView control, with a template that describes how a single TV show looks like. We display the show’s poster, along with some other info like the title, the runtime, the production country, etc. Since, due to the naming convention, the MainPageViewModel class is already set as BindingContext of the page, we can simply connect them by binding the ItemsSource property of the ListView with the TopSeries collection we’ve previously populated in the ViewModel.

Navigation with parameters

We’ve seen how to leverage the OnNavigatedTo() method to perform data loading, but often this method is useful also for another scenario: retrieving parameters passed by a previous page, which are usually needed to understand the current context (in our sample, in the detail page of our application we need to understand which TV Show the user has selected).

Prism support this feature thanks to a class called NavigationParameters, which can be passed as optional parameter of the NavigationAsync() method of the NavigationService and it’s automatically included as parameter of the OnNavigatedTo() and OnNavigatedFrom() events. Let’s see how to leverage this feature, by adding a detail page to our application, where to display some additional info about the selected show.

The first step is to add both a new page in the Views folder (called DetailPage.xaml) and a new class in the ViewModels folder (called DetailPageViewModel.cs). You need to remember also that every page needs to be registered in the container in the App class, inside the OnRegisterTypes() method:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage>();
    Container.RegisterTypeForNavigation<DetailPage>();
    Container.RegisterType<ITsApiService, TsApiService>();
}

Due to the naming convention, we don’t have to do anything special: the new page and the new ViewModel are already connected. Now we need to pass the selected item in the ListView control to the new page. Let’s see, first, how to handle the selection in the MainPage. We’ll get some help by a library created by my dear friend Corrado Cavalli, which allows to implement behaviors in a Xamarin Forms app. Among the available behaviors, one of them is called EventToCommand and it allows us to connect any event exposed by a control to a command defined in the ViewModel. We’re going to use it to connect the ItemTapped event of the ListView control (which is triggered when the user taps on an item in the list) to a command we’re going to create in the MainPageViewModel to trigger the navigation to the detail page.

You can install the package created by Corrado from NuGet: its name is Corcav.Behaviors. To use it, you need to add an additional namespace to the root of the MainPage, like in the following sample:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             xmlns:behaviors="clr-namespace:Corcav.Behaviors;assembly=Corcav.Behaviors"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="Info Series">

    ...

</ContentPage>

Then you can apply the behavior to the ListView control like you would do in a regular Windows app:

<ListView ItemTemplate="{StaticResource TopSeriesTemplate}"
          ItemsSource="{Binding Path=TopSeries}" RowHeight="200">
  <behaviors:Interaction.Behaviors>
    <behaviors:BehaviorCollection>
      <behaviors:EventToCommand EventName="ItemTapped" Command="{Binding GoToDetailPage}" />
    </behaviors:BehaviorCollection>
  </behaviors:Interaction.Behaviors>
</ListView>

Thanks to this behavior, we have connected the ItemTapped event of the ListView control to a command called GoToDetailPage, that we’re going to define in the ViewModel. From a framework point of view, Prism doesn’t do anything out of the ordinary to help developers implementing commands: it simply offers a class called DelegateCommand, which allows to define the operation to execute when the command is invoked and, optionally, the condition to satisfy to enable the command. If you have some previous experience with MVVM Light, it works exactly in the same way as the RelayCommand class. Here is how our command in the MainPageViewModel class looks like:

private DelegateCommand<ItemTappedEventArgs> _goToDetailPage;

public DelegateCommand<ItemTappedEventArgs> GoToDetailPage
{
    get
    {
        if (_goToDetailPage == null)
        {
            _goToDetailPage = new DelegateCommand<ItemTappedEventArgs>(async selected =>
            {
                NavigationParameters param = new NavigationParameters();
                param.Add("show", selected.Item);
                await _navigationService.NavigateAsync("DetailPage", param);
            });
        }

        return _goToDetailPage;
    }
}

The command we have created is a parametrized command; in fact, the property type is DelegateCommand<ItemTappedEventArgs>: this way, inside the method, we get access to the selected item, which is stored in the Item property. The method invoked when the command is triggered shows you how navigation with parameter works: first we create a new NavigationParameters object which, in the end, is nothing but a dictionary, where you can store key / value pairs. Consequently, we simply add a new item with, as key, the keyword show and, as value, the selected item, which type is SerieFollowersVM. This is the only difference compared to the navigation we’ve seen in the App class: the rest is the same, which means that we call the NavigateAsync() method of the NavigationService, passing as parameter the key that identifies the detail page (which is DetailPage) and the parameter.

Important! In the App class we were able to automatically use the NavigationService because it inherits from the PrismApplication class. If we want to use the NavigationService in a ViewModel (like in this case), we need to use the traditional approach based on dependency injection. The NavigationService instance is already registered in the Prism container, so we simply have to add an INavigationService parameter to the public constructor of the MainPageViewModel:

public MainPageViewModel(TsApiService apiService, INavigationService navigationService)
{
    _apiService = apiService;
    _navigationService = navigationService;
}

Now that we have performed the navigation to the detail page, we need to retrieve the parameter in the DetailPageViewModel class. The first step, like we did for the MainPageViewModel, is to let it inherit from the INavigationAware interface, other than the BindableBase class. This way, we have access to the OnNavigatedTo() event:

public class DetailPageViewModel : BindableBase, INavigationAware
{
    private SerieFollowersVM _selectedShow;

    public SerieFollowersVM SelectedShow
    {
        get { return _selectedShow; }
        set { SetProperty(ref _selectedShow, value); }
    }

    public DetailPageViewModel()
    {

    }

    public void OnNavigatedFrom(NavigationParameters parameters)
    {
            
    }

    public void OnNavigatedTo(NavigationParameters parameters)
    {
        SelectedShow = parameters["show"] as SerieFollowersVM;
    }
}

The previous code shows you how to handle the parameter we’ve received from the main page: the same NavigationParamaters object we’ve passed, in the MainPageViewModel, to the NavigateAsync() method is now passed as parameter of the OnNavigatedTo() method. As such, we can simply retrieve the item we’ve previously stored with the show key. In this case, since we are expecting an object which type is SerieFollowersVM, we can perform a cast and store it into a property of the ViewModel called SelectedShow. Thanks to this property, we can leverage binding to connect the various information of the selected show to the controls in the XAML page. Here is how the DetailPage.xaml looks like:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             Title="{Binding Path=SelectedShow.Name}"
             x:Class="InfoSeries.Views.DetailPage">

  <StackLayout>
    <Image x:Name="InfoPoster"
           Source="{Binding Path=SelectedShow.Images.Fanart}" Aspect="AspectFill" />
    <Label Text="{Binding Path=SelectedShow.Overview}" LineBreakMode="WordWrap" FontSize="13" TextColor="#98a6ad" Margin="15" />
  </StackLayout>

</ContentPage>

The content is very simple: we display an image of the show (stored in the SelectedShow.Images.Fanart property) and a brief description (stored in the SelectedShow.Overview property).

Wrapping up

In this post we’ve seen some basic concepts to handle navigation and dependency injection in a Xamarin Forms app created with Prism as MVVM framework. In the next post we’re going to see a couple of advanced scenarios, related to navigation and handling of platform specific code. You can find the sample app used for this post on my GitHub repository: https://github.com/qmatteoq/XamarinForms-Prism

Posted in Xamarin | Tagged , , , | Leave a comment

Prism for Xamarin Forms – An overview (Part 1)

Even if I understand that it may not be the right technology for every project, I’m a huge fan of Xamarin Forms. As you’ll probably know if you follow my blog, I’m a Windows Developer and Xamarin Forms allows me to use basically all my current skills (XAML, binding, MVVM, etc.) to create applications also for other popular mobile platforms like iOS and Android. Additionally, it gives me the chance (like with native Xamarin) to take advantage of platform specific features and, at the same time, to maintain a user experience which is coherent with the look & feel of the operating system.

I’ve recently used Xamarin Forms to create a porting for Android of my simple Qwertee Shirts app and the advantage was clear: I was able to reuse most of the backend code I’ve already wrote for the UWP version and my XAML knowledge but, at the end, I got an application that fully embraced, from a UI point of view, the new Material Design created by Google, so it doesn’t look “alien” like it often happens with cross platform applications based on other cross platform technologies.

Screenshot_2016-08-20-12-10-58 Screenshot_2016-08-20-12-11-19

However, I’m not only a Windows Developer, but also a MVVM enthusiast and I’ve blogged about this topic multiple times, covering multiple platforms and frameworks. If you’re new to the MVVM pattern, I suggest you to start from this post and move on with the rest of the series. As such, the first thing I did when I decided to resume working with Xamarin Forms to port my app was looking for the best way to reuse my MVVM knowledge to develop the project and, as usual, the choice was hard. In this case, it was even more complicated because Xamarin Forms, compared to other XAML technologies like WPF or UWP, is pretty new, so it was hard to find in the beginning a choice that completely satisfied me.

Don’t get me wrong, if you remember my posts about learning the MVVM pattern, you’ll know that I’m a huge fan of the flexibility offered by MVVM Light and Laurent Bugnion did a superb job to introduce typical MVVM concepts (like binding and commands) in platforms that don’t natively support them, like Android and iOS. However, Xamarin Forms is a bit different than standard Xamarin: it already offers the concepts we need to leverage the MVVM pattern, like binding, data context, dependency properties, behaviors, etc. In this scenario, MVVM Light is still a great choice but, however, you still have to reinvent the wheel to solve many common scenarios you have to deal with when you’re developing a XAML app, like handling navigation, getting access to navigation events in a ViewModel or passing parameters between one page to the other.

Even do it on purpose, right before starting my porting I saw a tweet by Brian Lagunas, one of the MVPs behind the Prism project, announcing a new version of Prism specific for Xamarin Forms. Just to refresh your mind, Prism is a MVVM framework that, originally, was created by the Patterns & Practices division by Microsoft and that, some times ago, has been turned into an open source project driven by the community. Prism has always been a great choice to implement the MVVM pattern in XAML based applications, but sometimes you may have faced the risk to make the project over complicated just to follow its naming conventions and rules (like the requirement of having a bootstrapper to initialize it, despite the fact that XAML based application already have a startup class called App).

After completing the porting, I’ve found myself very satisfied with the Prism approach for Xamarin Forms, so I’ve decided to share my experience with you, hoping that it will get you up & running quicker when you start working on a new Xamarin Forms project.

Creating the first project

The easiest way to create a Xamarin Forms project based on Prism is to use its own Visual Studio extension, that you can download from the Visual Studio Gallery. After you’ve installed it, you will find in Visual Studio a new section called Prism, with various templates for each supported technology. The template we’re interested into is called Prism Unity App (Forms):

prism1

Actually, this template has even an advantage over the standard Xamarin Forms template. As you can see from the image below, it allows you to choose which platform you want to target when you create your project, while the default Xamarin Forms template automatically creates a project for each supported platforms (Android, iOS, Windows Phone 8.1, Windows 8.1, UWP), even if you aren’t interested in targeting one of them.

Project Wizard

After you’ve hit the Create project, you will end up with a standard Xamarin Forms solution: one Portable Class Library and one specific project for each platform you’ve chosen. Additionally, the Portable Class Library will already contain:

  • A Views folder, where to place your pages. The template includes a default one, called MainPage.xaml
  • A ViewModels folder, where to place your ViewModels. The templates includes a default one, called MainPageViewModel.cs.
  • An App class already configured to initialize the Prism infrastructure.

Here is how your default project will look like:

prism2

To demo Prism for Xamarin Forms, I’m going to create a simple client for TrackSeries, a TV Show website created by my great friends and colleagues Adrian Fernandez Garcia and Carlos Jimenez Aliaga.

Let’s start from the beginning and see which references have been automatically added by the template to the project:

prism3

As you can see, other than the standard Xamarin Forms NuGet package, Prism requires two packages: a Core one (which is in common across every platform) and a Forms one (which, instead, contains the specific helpers and services for Xamarin Forms). By default, the standard template leverages Unity as dependency injection container, so you’ll find installed also a bunch of other packages like Unity, Prism.Unity.Forms and CommonServiceLocator. However, if you don’t like Unity, Prism for Xamarin Forms offers some additional packages to integrate other popular dependency injection containers, like Ninject or Autofac.

The App class

One of the biggest changes compared to the old Prism versions is the removal of the bootstrapper concept, which was a dedicated class of the project that took care of initializing all the Prism infrastructure. Xamarin Forms (as every other XAML technology) already has an initializer class: the App one, which is included in the Portable Class Library, so the team has decided to leverage it instead of asking to the developer to create a new one. By default, this class inherits from the Application class. To properly support Prism, we need to change this and let the App class inherit from the PrismApplication one by:

  • In the App.xaml file, adding a new identifier for the namespace Prism.Unity and replacing the root Application node with the PrismApplication one.
<?xml version="1.0" encoding="utf-8" ?>
<prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                        xmlns:prism="clr-namespace:Prism.Unity;assembly=Prism.Unity.Forms"
                        x:Class="InfoSeries.App">

</prism:PrismApplication>
  • In the App.xaml.cs file, we need to change the default inheritance from Application to PrismApplication.
public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MainPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>();
    }
}

Additionally, the App class has three distinctive features:

  • It has a base constructor, which takes an IPlatformInitializer object as parameter.
  • It has a method called OnInitialized(), where we initialize the Forms infrastructure (by calling the InitializeComponent() method) and we trigger the navigation to the main page of the app (we’ll see later in details how navigation works).
  • It has a method called RegisterTypes(), which is where we register in the dependency injection container (in this case, Unity) every page and every service required by our application.

The IPlatformInitializer parameter is null by default, but it can be leveraged in case you need to register in the dependency container some specific classes that exists only in a platform specific project. You will find, in fact, that every platform specific project has its own custom initializer class (AndroidInitializer for Android, UwpInitializer for UWP, etc.) which, however, by default has an empty implementation of the RegisterTypes() method. Here is, for example, how the MainPage.xaml.cs of the UWP project looks like:

public sealed partial class MainPage
{
    public MainPage()
    {
        this.InitializeComponent();

        LoadApplication(new DeepNavigation.App(new UwpInitializer()));
    }
}

public class UwpInitializer : IPlatformInitializer
{
    public void RegisterTypes(IUnityContainer container)
    {

    }
}

Connecting Views and ViewModels

As you should already know if you have some previous experience with MVVM , the key to make the pattern working is to connect the ViewModel with its own View through binding. The only difference in a Xamarin Forms app compared to a Windows app is that the property to define the context is called BindingContext and not DataContext. Prism makes use of a simple naming convention to automatically assign a ViewModel to its View:

  • The XAML page should be stored into a folder of the project called Views
  • The ViewModel should be stored into a folder of the project called ViewModels and it needs to have the same name of the page plus the suffix ViewModel (so, for example, the ViewModel connected to the MainPage.xaml will be called MainPageViewModel).

As you can see, this is the exact infrastructure that the Prism template has created for us. Every page that we add to our application needs to be registered in the container, so that we can properly handle the navigation. To register it, we can leverage the RegisterTypes() method of the App class and use one of the methods offered by the Container called RegisterTypeForNavigation<T>, where T is the type of the page. In the starting template, we have just one page called MainPage, so it’s the only one that is automatically registered when the application starts. Here you can notice probably one of the biggest differences between Prism and other MVVM frameworks. With other toolkits, you are used to register in the container only the ViewModels and, eventually, all the services related to them. With Prism, instead, you just register the page’s type: it’s up to Prism to automatically register in the container also the ViewModel connected to the View. As you can see in the sample code, in fact, we have registered the MainPage class and not the MainPageViewModel one.

If you aren’t a fan of the naming convention approach, you aren’t forced to use it: in fact, the RegisterTypeForNavigation() method has another variant, which signature is RegisterTypeForNavigation<T, Y>(), where T is the page’s type and Y is the ViewModel’s type we want to set as BindingContext. So, for example, if you want to connect your MainPage to a ViewModel called MyCustomViewModel, it’s enough to register it using the following code:

protected override void RegisterTypes()
{
    Container.RegisterTypeForNavigation<MainPage, MyCustomViewModel>();
}

In the OnInitialized() method you can see a preview of how navigation works by default: every time you call the RegisterTypeForNavigation<T> method, Prism registers into the NavigationService a reference to that page using, as key, a string with the same type name. As such, since our page’s type is MainPage, we need to pass the string “MainPage” as parameter of the NavigateAsync() method to trigger the navigation to that page. If, by any chance, we want to override this behavior, we can pass as parameter of the RegisterTypeForNavigation<T>() a custom string and use it for the subsequent navigations, like in the following sample, where we have replaced the key “MainPage” with the “MyCustomPage” one.

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null) : base(initializer) { }

    protected override void OnInitialized()
    {
        InitializeComponent();

        NavigationService.NavigateAsync("MyCustomPage");
    }

    protected override void RegisterTypes()
    {
        Container.RegisterTypeForNavigation<MainPage>("MyCustomPage");
    }
}

However, in the next posts we’ll see more details about how to handle navigation in a more advanced way.

The ViewModel

One of the features I’ve appreciated most of Prism for Xamarin Forms is that it doesn’t require us to do any change in XAML page to support it (for example, there are other MVVM frameworks which require you to change the ContentPage type with a custom one). You will only find, in the MainPage.xaml file, a specific Prism attribute, as property of the ContentPage entry, called ViewModelLocator.AutowireViewModel:

<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="InfoSeries.Views.MainPage"
             Title="MainPage">
  <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
    <Label Text="{Binding Title}" />
  </StackLayout>
</ContentPage>

This property takes care of connecting the View with the ViewModel: when it’s set to true, the ViewModel will be automatically set as BindingContext of the View if we have respected the naming convention previously described. However, one of the changes introduced in Prism 6.2 is that this property isn’t required anymore, unless you want to explicitly disable the naming convention by setting it to false. The standard template adds it to give a more complete sample, but you can safely remove it.

A key feature offered by every MVVM framework is a class to use for our ViewModels to give quick access to the most used features, like the implementation of the INotifyPropertyChanged interface. Prism doesn’t make any exception and it offers a class called BindableBase, which our ViewModels can inherit from:

public class MainPageViewModel : BindableBase
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
    }

    public MainPageViewModel()
    {

    }
}

Thanks to this class, whenever we need to create a property that implements the INotifyPropertyChanged interface (so that it can propagate its changes through the binding channel), we can simply use the SetProperty() method in the setter of the property. This method will take care of storing the value and, at the same time, sending a notification to all the controls that are in binding with this property that its value has changed, so they need to update their layout.

The sample app created by template does exactly this: it creates a property called Title, which is connected through binding to a Label control in the XAML page. Whenever we change the value of the property, we will see the UI updated in real time. To be honest, the sample app shows also something different: it sets the value of the Title property in a method called OnNavigatedTo() and it parses some parameters. We’re going to see how this approach works more in details in the next post.

In the next post

In this post we have just scratched the surface and we understood the basic concept behind a Xamarin Forms application created with Prism. In the next post we’ll see some more advanced concepts, like handling navigation in a ViewModel or registering additional services in the dependency container.

Posted in Xamarin | Tagged , , , | 1 Comment