In this blog, I’ll show you how easy it is to create an Android and iOS application using Xamarin Forms while utilizing Prism.
What is Xamarin.Forms?
Xamarin Forms is a platform that allows developers to create native Android, iOS, and Windows applications while using the beloved C# programming language.
An attractive feature of Xamarin Forms is that it uses a shared C# codebase to create a native user interface specific to their platform. Out of the box, Xamarin provides large collections of controls to get started. It also has the ability to access native platform features, such as camera access, GPS, text to speech, etc, by using the Dependency Service.
What is Prism?
According to the Prism website, Prism is defined as “a framework for building loosely coupled, maintainable, and testable XAML applications in WPF, Windows 10 UWP, and Xamarin Forms. Prism provides an implementation of a collection of design patterns that are helpful in writing well-structured and maintainable XAML applications, including MVVM, dependency injection, commands, EventAggregator, and others.”
In other words, Prism helps users to write better code.
Prerequisites
- Visual Studio Pro 2017
- Prism Framework
- Prism Template Pack (Visual Studio Extensions)
- Android Emulator or Android Phone
- XAML Knowledge
To see the source code associated with this demo, please see this repository: https://github.com/ryandnguyen/SimpleBlog.
Initial Setup
- Open Visual Studio. Create a new “Prism Blank App (Xamarin.Forms).” This requires “Prism Template Pack” to be installed.
- The selection screen offers three different types of dependency injections (DI) to pick from, AutoFac, Dryloc, and Unity.
You can read more about each type of dependency injections and what works best for you. In this article, we will not focus on the different types of DI and what advantages or disadvantages one has over the other.
- The new App solution would look something like this:
- Make sure everything works by building and compiling then deploying the app. After deploying the app to your emulator or phone, you should have something very basic and simple like the image below.
Source Code Layout
The solution contains multiple projects consisting of a C# shared library, Android, and iOS. The shared library project is where all the business logic and coding implementation would lie. The shared library project also shared across all platforms. Each dedicated project (Android, iOS, Windows) allows the end user to develop native codes that are not available in Xamarin Forms.
Views
This folder contains all your views, essentially the User Interface (UI) for your applications. The View
is responsible for displaying information to the user and fire events in response to user interactions. The View is written also in Xamarin XAML. More information on Xamarin Forms UI can be found here.
The Prism Template Pack offers users a variety of page templates that could be selected from. Such items include: Prism ViewModel
, CarouselPage
, ContentPage
, MasterDetailPage
, and NavigationPage
. More information can be obtained here about each type of page. The template helps users by automatically creating the View
, Viewmodel
, and registering it in the App.cs
file.
ViewModels
This folder contains all the ViewModels
for your views. Following the MVVM pattern, each view would contain a ViewModel
. The ViewModels
would essentially serve as the business logic behind the user interface. Prism would automatically wire your ViewModel
by looking at all the ViewModels
and matching them to the View
with the corresponding name. For example, if there’s a ViewModel
called MainPageViewModel
, it would try to find the View
that’s called MainPage
.
Let’s Code
Let’s start by expanding our app to something that’s a bit more than a simple label that shows “Welcome to Xamarin Forms and Prism!”.
When we first created our app, the Prism Template automatically creates a Content Page called Mainpage.xaml
. This is by default the main page which would display on startup.
Let’s begin by adding a ListView
and setting the ItemSource
to a collection of blogs.
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleBlog.Views.MainPage" xmlns:local="clr-namespace:SimpleBlog.Behaviors" Title="{Binding Title}"> <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"> <ListView ItemsSource="{Binding Blogs, Mode=TwoWay}" HasUnevenRows="True" SelectedItem="{Binding SelectedBlog}" local:ItemTappedAttached.Command="{Binding NavigateToBlogCommand}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Frame Margin="10" VerticalOptions="FillAndExpand"> <Frame.Content> <StackLayout> <Label Text="{Binding BlogTitle}"/> <BoxView Color="LightGray" VerticalOptions="FillAndExpand" HeightRequest="1" HorizontalOptions="FillAndExpand" Margin="0,5,0,0" /> <Label Text="{Binding BlogDescription}" LineBreakMode="WordWrap" HeightRequest="100"></Label> </StackLayout> </Frame.Content> </Frame> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
The next step is to update the MainPageViewModel
to include all the properties and commands that the view is bound to. This includes the collections of Blogs
, the SelectedBlog
and the NavigateToBlogCommand
. The Blogs
would serve as the collection of blogs for the user to see. The SelectedBlog
would serve as the selected item the user selected. The NavigateToBlogCommand
is the action that will be performed when the user selects a blog.
For the purpose of making this app simple, I decided to return a list of hard-coded blogs instead of obtaining it from the database or a service.
using Prism.Commands; using Prism.Navigation; using SimpleBlog.Models; using System; using System.Collections.Generic; namespace SimpleBlog.ViewModels { public class MainPageViewModel : ViewModelBase { public DelegateCommand NavigateToBlogCommand { get; private set; } private List<Blog> _blogs = new List<Blog>() { new Blog { BlogDescription = "olestie lectus rhoncus non. Ut eget metus neque. Cras laoreet quam ligula, in ultricies enim lobortis vitae. Proin sed justo vel quam luctus bibendum. Praesent gravida vehicula nunc, eu aliquet elit vestibulum non. Aliquam aliquam fringilla nunc, eget tincidunt dui finibus vel.", BlogTitle = "Blog 1", CreatedDate = DateTime.Now, CreatedBy = "Ryan Nguyen" }, new Blog { BlogDescription = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam a sollicitudin erat. Vestibulum dapibus sagittis risus, sit amet molestie lectus rhoncus non. Ut eget metus neque. Cras laoreet quam ligula, in ultricies enim lobortis vitae. Proin sed justo vel quam luctus bibendum. Praesent gravida vehicula nunc, eu aliquet elit vestibulum non. Aliquam aliquam fringilla nunc, eget tincidunt dui finibus vel. Ut fermentum viverra justo, a vehicula dui dignissim non. Aenean posuere vestibulum felis, eu fringilla nulla. Nam interdum enim nec risus cursus tempus. Integer vestibulum hendrerit metus, a venenatis justo molestie at. Vestibulum nec libero in velit pulvinar pretium non in enim. Nulla pulvinar auctor dolor, eu laoreet quam vehicula nec. Cras vehicula fringilla massa, vitae molestie lectus dignissim sed. Integer suscipit auctor est, eu bibendum turpis aliquam vitae.", BlogTitle = "Blog 2", CreatedDate = new DateTime(2017,12,30), CreatedBy = "Adam Costenbader" }, new Blog { BlogDescription = "Etiam a sollicitudin erat. Vestibulum dapibus sagittis risus, sit amet molestie lectus rhoncus non. Ut eget metus neque. Cras laoreet quam ligula, in ultricies enim lobortis vitae. Proin sed justo vel quam luctus bibendum. Praesent gravida vehicula nunc, eu aliquet elit vestibulum non. Aliquam aliquam fringilla nunc, eget tincidunt dui finibus vel. Ut fermentum viverra justo, a vehicula dui dignissim non. Aenean posuere vestibulum felis, eu fringilla nulla. Nam interdum enim nec risus cursus tempus. Integer vestibulum hendrerit metus, a venenatis justo molestie at. Vestibulum nec libero in velit pulvinar pretium non in enim. Nulla pulvinar auctor dolor, eu laoreet quam vehicula nec. Cras vehicula fringilla massa, vitae molestie lectus dignissim sed. Integer suscipit auctor est, eu bibendum turpis aliquam vitae.", BlogTitle = "Blog 3", CreatedDate = new DateTime(2017,11,30), CreatedBy = "Rusty Divine" }, new Blog { BlogDescription = "molestie lectus rhoncus non. Ut eget metus neque. Cras laoreet quam ligula, in ultricies enim lobortis vitae. Proin sed justo vel quam luctus bibendum. Praesent gravida vehicula nunc, eu aliquet elit vestibulum non. Aliquam aliquam fringilla nunc, eget tincidunt dui finibus vel. Ut fermentum viverra justo, a vehicula dui dignissim non. Aenean posuere vestibulum felis, eu fringilla nulla. Nam interdum enim nec risus cursus tempus. Integer vestibulum hendrerit metus, a venenatis justo molestie at. Vestibulum nec libero in velit pulvinar pretium non in enim. Nulla pulvinar auctor dolor, eu laoreet quam vehicula nec. Cras vehicula fringilla massa, vitae molestie lectus dignissim sed. Integer suscipit auctor est, eu bibendum turpis aliquam vitae.", BlogTitle = "Blog 4", CreatedDate = new DateTime(2017,10,30), CreatedBy = "Linh Nguyen" }, }; private Blog _selectedBlog; public Blog SelectedBlog { get { return _selectedBlog; } set { SetProperty(ref _selectedBlog, value); } } public List<Blog> Blogs { get { return _blogs; } set { SetProperty(ref _blogs, value); } } public MainPageViewModel(INavigationService navigationService) : base(navigationService) { Title = "Blogs"; NavigateToBlogCommand = new DelegateCommand(NavigateToBlog, () => SelectedBlog != null).ObservesProperty(() => SelectedBlog); } private void NavigateToBlog() { var parameter = new NavigationParameters(); parameter.Add("Blog", SelectedBlog); NavigationService.NavigateAsync("Blog", parameter); } } }
At this point, the app should be a scrollable list of blog summaries on the main page.
Navigation
The next step is to allow the user to select the blog and navigate to see the blog details rather than just a snippet. In order to navigate to see the blog details, the MainPageViewModel
utilizes the NavigationService
service. This service is dependency injected in the constructor, which makes it easily accessible. This service also allows you to pass parameters when navigating.
Looking at the NavigateToBlog
method in the MainPageViewModel
, we are passing in the SelectedBlog
object as a parameter. The Blog
page would then consume the object to render the UI to display the blog details. However, since the Blog
page does not exist quite yet, the first thing we want to do is create it.
Under the Views
folder, add a new Prism Content Page
called Blog
. This would automatically create the BlogViewModel
and automatically register the new page in the App.cs
file.
Simply update the Blog
and BlogViewModel
to the following:
Blog View
<?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 Title}" x:Class="SimpleBlog.Views.Blog"> <Frame Margin="10" VerticalOptions="FillAndExpand"> <Frame.Content> <StackLayout VerticalOptions="FillAndExpand"> <StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal"> <Label Text="{Binding BlogDetail.BlogTitle}" HorizontalOptions="StartAndExpand"/> <Label Text="{Binding BlogDetail.CreatedBy, StringFormat='Author: {0}'}" HorizontalOptions="End"/> </StackLayout> <BoxView Color="LightGray" HeightRequest="1" HorizontalOptions="FillAndExpand" Margin="0,5,0,0" /> <Label Text="{Binding BlogDetail.BlogDescription}" LineBreakMode="WordWrap" VerticalOptions="FillAndExpand"></Label> <Label Text="{Binding BlogDetail.CreatedDate, StringFormat='Date: {0: MM-dd-yyy}'}" VerticalOptions="End" HorizontalOptions="EndAndExpand"/> </StackLayout> </Frame.Content> </Frame> </ContentPage>
BlogViewModel
using Prism.Navigation; using SimpleBlog.Models; namespace SimpleBlog.ViewModels { public class BlogViewModel : ViewModelBase { public BlogViewModel(INavigationService navigationService) : base(navigationService) { } private Blog _blogDetail; public Blog BlogDetail { get { return _blogDetail; } set { SetProperty(ref _blogDetail, value); } } public override void OnNavigatedTo(NavigationParameters parameters) { BlogDetail = (Blog)parameters["Blog"]; Title = BlogDetail.BlogTitle; base.OnNavigatedTo(parameters); } } }
To intercept the parameters which are being sent, we need to override the OnNavigatedTo
method. This would allow us to obtain the parameters and update our binding object to allow the View
to display the information.
Summary
Xamarin Forms is a handy platform for creating mobile applications using the .NET framework. It has the flexibility of building the app once and then it’s shared among other platforms like Android, iOS, and Windows Phone. I also feel that Prism complements Xamarin forms by assisting users with code maintainability, best practices, and ease of use.
For more information, use the following links:
- Xamarin Forms: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/get-started/
- Prism: http://prismlibrary.github.io/docs/xamarin-forms/Getting-Started.html
- Demo Source Code: https://github.com/ryandnguyen/SimpleBlog
I hope that you’ve found this demonstration helpful and consider giving these tools a try!