Smart phones are everywhere today, in fact you can’t walk down the street without spotting someone glued to that little screen; interacting with one of the thousands of apps available to download and enjoy. But, have you ever wondered what involved with writing an app yourself?
In this tutorial for beginners we’re going to build a simple app using Xamarin Forms from Microsoft which has the benefit of using a single codebase which can work across Android and iOS; which means you don’t have to worry about learning two different languages or writing the same code twice! The screenshots for this tutorial have been created using a Mac and the simulator device is the iOS Simulator but don’t let that discourage you if you’re using a Windows machine, you can still complete the tutorial by using an Android Virtual Device.
So, let’s get started!
The first thing you’ll need to do is install Visual Studio Community, during the installation process make sure you select the option to install Android + Xamarin.Forms and iOS + Xamarin.Forms on Visual Studio for Mac or, if you’re using Windows, Mobile development with .NET on Visual Studio.
Once you’ve finished installing Visual Studio, we’ll move on.
Step 1. Creating a Solution
The first thing we’ll need to do is create a Solution; a Solution is where we’ll keep all of our code and will be separated into separate Projects, but we’ll go into that in more detail later. For now, click on the File drop down menu and select New Solution…
Step 2. Choosing a Solution
You’ll be presented with the screen shown below asking you to choose a template, I’ve never been one for taking shortcuts when there’s something that can be learned, so let’s select a Blank Forms App then click Next.
Step 3. Configuring our app
The next screen lets us configure our app by specifying a name, choosing target platforms and the method for sharing our code between Android and iOS. You can check the screenshot or copy and paste the options below:
- App Name: My Library
- Organization Identifier: com.mycompany
- Target Platforms: Android and iOS
- Shared Code: Use .NET Standard
Once you’re happy, click Next.
Step 4. Finishing up configuration
The final screen is used to specify our Solution and Project names, select a location for our work and define whether we want to use Version Control and create an App Center Test. Since this is a simple app we’ll dispense with the last two options and just worry about the naming and location:
- Project Name: MyLibrary
- Solution Name: MyLibrary
- Location: <Your desktop or some other place you like to save files>
Finish up by clicking Create.
Step 5. Getting better acquainted
Once the set-up process has been completed you’ll be presented with a screen similar to the one below; you’ll notice there are two tabs open called MainPage.xaml and MainPage.xaml.cs, these are the two files that represent the first page your app will load. There are two because one contains declarative XAML used to layout controls and the other “code-behind” file contains imperative C# code used to control specific actions. You will also see the Solution Explorer displayed on the side of the screen which provides a graphical representation of your Solution, as shown in the list below:
- Solution
- MyLibrary
- MyLibrary
- Getting Started
- Dependencies
- App.xaml
- App.xaml.cs
- MainPage.xaml
- MainPage.xaml.cs
- MyLibrary.Android
- MyLibrary.iOS
- MyLibrary
- MyLibrary
The more eagle-eyed of you might have noticed there is an App.xaml and App.xaml.cs code-behind file, more on those later.
Step 6. Running our app
OK, the temptation is too great, before we start writing any code let’s see our blank app working in a simulator! If you Visual Studio is working as expected you should be able to just click on the ‘play’ button shown in the screenshot and our app should just begin to build; if that doesn’t happen make sure you have selected the correct target from the dropdown menu. The build target should be MyLibrary.iOS or MyLibrary.Android, the process should be Debug and the deployment target should be a Simulator (iOS) or Virtual Device (Android).
Assuming your app has built and deployed as expected, this is what you should see; pretty heat, huh?
Step 7. Adding a list
That’s great, we’ve got this far and we know the app runs out of the box, now it’s time to start writing some code! Go back to Visual Studio and click the ‘stop’ button which was the ‘play’ button previously.
All apps contain controls, without them apps wouldn’t be the run-away success they are because no one would be able to use them!
So let’s add our first control.
Visual Studio should still have the MainPage.xaml file open but if it doesn’t double click on it in the Solution Explorer to open it. XAML stands for eXtensible Application Markup Language and was released by Microsoft in 2008 as a clean and simple way for app developers to create layouts in a similar fashion to HTML. If you take a quick look at the code you’ll spot on the first line that XAML is actually XML.
MainPage.xaml contains three nested visual elements, a visual element is a catch-all name for anything we use to provide layout in Xamarin Forms, in fact it is the basic class that all controls and views derive from.
- ContentPage – used to display individual pages or screens in Xamarin Forms
- StackLayout – used to display controls in a horizontal or vertical stack
- Label – used to display text on the screen
- StackLayout – used to display controls in a horizontal or vertical stack
We’re going to replace the Label with something a little more useful for our app, so delete the text below.
<!-- Place new controls here --> <Label Text="Welcome to Xamarin.Forms!" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
And replace it with this text.
<ListView> <ListView.ItemsSource> <x:Array Type="{x:Type x:String}"> <x:String>A Tale of Two Cities</x:String> <x:String>To Kill a Mockingbird</x:String> <x:String>Of Mice and Men</x:String> <x:String>Pride and Prejudice</x:String> <x:String>Ulysses</x:String> </x:Array> </ListView.ItemsSource> </ListView>
Then save the file but clicking on File > Save, Cmd+S (Mac) or Ctrl+S (Windows) and run the app again by clicking on the ‘play’ button again. Here’s what you should see.
Well done, we’ve now got a list of book titles on our main page, but it would be better if we could allow users of our app to add their own books to the list. So let’s press on…
Step 8: Adding Navigation
At the moment we have a single page app, but most modern apps have many more pages; so we’re going to need to give our users a way of moving back and forth between pages, we do this using navigation.
We add navigation to an app using a NavigationPage, which wraps all our other pages and provides a means of moving between them; to do this we need to open the App.xaml.cs file and replace the following line:
MainPage = new MainPage();
With this line:
MainPage = new NavigationPage(new MainPage());
As you might have spotted, the line literally wraps an instance of our MainPage with a NavigationPage instance.
The next step in adding navigation is to give our existing pages a title, so we make it easy for our app’s users to see what page they’re on; since we only have the one page at the moment this will be quick. Open MainPage.xaml.cs and add the following parameter just before the closing angle-bracket > at the end of the line that begins <ContentPage:
Title="My Library"
So the line should appear like this (I’ve added carriage returns to make the line easier to read):
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:MyLibrary" x:Class="MyLibrary.MainPage" Title="My Library">
Now hit the ‘play’ button and you should see that our app now has navigation.
Step 9. Create a new page
So, let’s add a new page; you can do this by clicking on File > New File… or right-clicking on the MyLibrary project and selecting New File…
On the New File dialog box, select the Forms option followed by the Forms ContentPage XAML file type, then enter AddBookPage in the Name text box and click New.
Visual Studio will then create the AddBookPage.xaml and AddBookPage.xaml.cs files in the MyLibrary project.
Let’s add some more code, open the AddBookPage.xaml file and replace the contents with the following code:
<?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="MyLibrary.AddBookPage" Title="Add Book"> <ContentPage.Content> <StackLayout Margin="10"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Grid.Column="0" Grid.Row="0" Text="Title"/> <Entry Grid.Column="1" Grid.Row="0" Placeholder="Title"/> <Label Grid.Column="0" Grid.Row="1" Text="Author"/> <Entry Grid.Column="1" Grid.Row="1" Placeholder="Author"/> <Label Grid.Column="0" Grid.Row="2" Text="ISBN"/> <Entry Grid.Column="1" Grid.Row="2" Placeholder="ISBN"/> </Grid> <Button Text="Add Book"/> </StackLayout> </ContentPage.Content> </ContentPage>
What we’ve added here is a StackLayout which wraps a Grid which we use to layout three Label controls, three Entry controls and a Button. The Grid is configured to contain two columns of equal width which fills the width of the screen, there’s no need to specify how many rows we will need as Xamarin is clever enough to work out we’ll need three when we assign visual elements to them using the Grid.Row parameter. Notice we have also given the page title of Add Book, this will show up in the navigation bar when being viewed by the user.
Now we need to give our user a way to open the Add Book page, we do this by adding a toolbar item that appears in navigation bar of the app’s Main Page. Start by opening the MainPage.xaml file and add the following code between the ContentPage and StackLayout elements:
<ContentPage.ToolbarItems> <ToolbarItem x:Name="_addBook" Name="Add Book"></ToolbarItem> </ContentPage.ToolbarItems>
So the page should now look like this:
<?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:MyLibrary" x:Class="MyLibrary.MainPage" Title="My Library"> <ContentPage.ToolbarItems> <ToolbarItem x:Name="_addBook" Name="Add Book"></ToolbarItem> </ContentPage.ToolbarItems> <StackLayout> <ListView> <ListView.ItemsSource> <x:Array Type="{x:Type x:String}"> <x:String>A Tale of Two Cities</x:String> <x:String>To Kill a Mockingbird</x:String> <x:String>Of Mice and Men</x:String> <x:String>Pride and Prejudice</x:String> <x:String>Ulysses</x:String> </x:Array> </ListView.ItemsSource> </ListView> </StackLayout> </ContentPage>
So, we’ve declared that a toolbar item should appear, but as yet it doesn’t know what to do when it’s clicked, so let’s fix that now; open the MainPage.xaml.cs file and, after the line that reads InitializeComponent();, add the following text:
_addBook.Clicked += (object sender, EventArgs e) => { Navigation.PushAsync(new AddBookPage()); };
So the file should now look like this:
using System; using Xamarin.Forms; namespace MyLibrary { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); _addBook.Clicked += (object sender, EventArgs e) => { Navigation.PushAsync(new AddBookPage()); }; } } }
As you might have noticed, the toolbar item’s x:Name property was defined as _addBook in the XAML file, so that’s what we have referenced in the code-behind file. Here we assign a function to the Clicked EventHandler which adds – or pushes – an instance of the AddBookPage onto the top of the navigation stack. The stack behaves like a list of pages, the last one added is the one that is currently displayed and the user can pop pages off the list to return to previous ones, like they would sing a back button on a web browser.
Now hit the ‘play’ button and you should see that our app has a toolbar item called Add Book that, when clicked, displays the Add Book page.
10. Adding a Model, View Model and binding
Now we have pages to display a list of books and add new books, we now need a way to store book information. We can do this for now by keeping them in memory; the next tutorial will dive into persistent storage using a database.
Let’s first add a place to save the fields we have defined in the AddBookPage for each book, we’ll do this by creating what is known as a model; so go ahead and add a new file but, instead of choosing a Forms Content Page XAML type, we’ll create an Empty Class and call it Book.
Inside the Book.cs file replace the contents with the following code:
namespace MyLibrary { public class Book { public string Title { get; set; } public string Author { get; set; } public string ISBN { get; set; } } }
We have create a model for a book that contains three properties, Title, Author, and ISBN; they have be given public access with a getter and setter, this means we will be able to bind them to the Entry controls we added earlier in the AddBookPage.xaml file.
So, where are we now? We have a way of taking book properties from the user by the AddBookPage and a way of storing them in memory; now we need a way of binding them together, we’ll do this using a View Model. Add a new Empty Class and call it AddBookPageViewModel, then inside the AddBookPageViewModel.cs file that you’ve just created, replace the contents with the following code.
namespace MyLibrary { public class AddBookPageViewModel { public Book Book { get; set; } public AddBookPageViewModel() { Book = new Book(); } } }
We’ve given the View Model a property called Book and in the AddBookPageViewModel‘s constructor we’ve created a new instance of Book and assigned it to the property. Now, let’s bind the View Model’s properties to the AddBookPage. Open the AddBookPage.xaml.cs file and add the following code after the line that starts InitializeComponent():
BindingContext = new AddBookPageViewModel();
So the contents should now look like this:
using Xamarin.Forms; namespace MyLibrary { public partial class AddBookPage : ContentPage { public AddBookPage() { InitializeComponent(); BindingContext = new AddBookPageViewModel(); } } }
As you can see, we’ve told the page that the BindingContext should be a new instance of the AddBookPageViewModel, a BindingContext is an object that contains properties we can bind to on a page; so let’s bind to them now. Open the AddBookPage.xaml file and update the Entry controls for Title, Author, and ISBN by adding the following properties for each one in turn:
Text="{Binding Book.Title}" Text="{Binding Book.Author}" Text="{Binding Book.ISBN}"
So the file should now look like this:
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyLibrary.AddBookPage" Title="Add Book"> <ContentPage.Content> <StackLayout Margin="10"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Grid.Column="0" Grid.Row="0" Text="Title"/> <Entry Grid.Column="1" Grid.Row="0" Placeholder="Title" Text="{Binding Book.Title}"/> <Label Grid.Column="0" Grid.Row="1" Text="Author"/> <Entry Grid.Column="1" Grid.Row="1" Placeholder="Author" Text="{Binding Book.Author}"/> <Label Grid.Column="0" Grid.Row="2" Text="ISBN"/> <Entry Grid.Column="1" Grid.Row="2" Placeholder="ISBN" Text="{Binding Book.ISBN}"/> </Grid> <Button Text="Add Book"/> </StackLayout> </ContentPage.Content> </ContentPage>
11. Here’s where it gets tricky
So, we now have a page to display a list of books, a page to let us add a book, a model to contain the details of a book, and a view model to bind them together; but without the use of a database how should we store the books we add in memory? There are a number of ways this can be achieved but the easiest way for the interests of this tutorial is to create a place that exists for as long as the app is running where we can store the details of our books.
Open the App.xaml.cs file and add the following code at the beginning of the file:
using System.Collections.ObjectModel;
Then add this property after the opening brace of class declaration that begins public partial class App:
public ObservableCollection<Book> Books { get; } = new ObservableCollection<Book> { new Book { Title = "A Tale of Two Cities" }, new Book { Title = "Of Mice and Men" }, new Book { Title = "Pride and Prejudice" }, new Book { Title = "To Kill a Mockingbird" }, new Book { Title = "Ulysses" } };
So the whole file should look like this:
using System.Collections.ObjectModel; using Xamarin.Forms; using Xamarin.Forms.Xaml; [assembly: XamlCompilation(XamlCompilationOptions.Compile)] namespace MyLibrary { public partial class App : Application { public ObservableCollection<Book> Books { get; } = new ObservableCollection<Book> { new Book { Title = "A Tale of Two Cities" }, new Book { Title = "Of Mice and Men" }, new Book { Title = "Pride and Prejudice" }, new Book { Title = "To Kill a Mockingbird" }, new Book { Title = "Ulysses" } }; public App() { InitializeComponent(); MainPage = new NavigationPage(new MainPage()); } protected override void OnStart() { // Handle when your app starts } protected override void OnSleep() { // Handle when your app sleeps } protected override void OnResume() { // Handle when your app resumes } } }
We’ve just added an ObservableCollection to the App class, an ObservableCollection is a list which reports to anything that is bound to it when it has been updated; which means we’ll be able to automatically update our list of books on the MainPage.xaml page when we add one without any extra code. So let’s go ahead and bind the two together.
Create a new Empty Class and call is MainPageViewModel then replace its contents with the following code:
using Xamarin.Forms; namespace MyLibrary { public class MainPageViewModel { public App App { get; private set; } public MainPageViewModel() { App = (App)Application.Current; } } }
We have created a property called App that references our main App instance, now we need to update our MainPage.xaml.cs file to use this view model as a BindingContext; go head and open it and add the following line after the _addBook.Clicked code we added before:
BindingContext = new MainPageViewModel();
The whole file should now look like this:
using System; using Xamarin.Forms; namespace MyLibrary { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); _addBook.Clicked += (object sender, EventArgs e) => { Navigation.PushAsync(new AddBookPage()); }; BindingContext = new MainPageViewModel(); } } }
All we need to do now is update our ListView in MainPage.xaml so it uses the ObservableCollection instead of the static array of books we added earlier; go ahead and open the file and replace the ListView with the following code:
<ListView ItemsSource="{Binding App.Books}"> <ListView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding Title}"/> </DataTemplate> </ListView.ItemTemplate> </ListView>
So the whole file should now look like this:
<?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:MyLibrary" x:Class="MyLibrary.MainPage" Title="My Library"> <ContentPage.ToolbarItems> <ToolbarItem x:Name="_addBook" Name="Add Book"></ToolbarItem> </ContentPage.ToolbarItems> <StackLayout> <ListView ItemsSource="{Binding App.Books}"> <ListView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding Title}"/> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
As you can see, we’ve replaced the ItemsSource property with a binding to the Books ObservableCollection in the App instance we referenced in the view model. We’ve also created a ItemTemplate which contains a TextCell that we have bound to the Title property of the Book object.
Step 12. Adding a book to the list
Right, let’s get this app finished, all we need to do now is add the book to the list; so let’s open the AddBookPageViewModel.cs file and add the following lines after the AddBookPageViewModel constructor:
public void AddBook() { ((App)Application.Current).Books.Add(Book); }
So now the file should look like this:
using Xamarin.Forms; namespace MyLibrary { public class AddBookPageViewModel { public Book Book { get; set; } public AddBookPageViewModel() { Book = new Book(); } public void AddBook() { ((App)Application.Current).Books.Add(Book); } } }
We’ve added a function that, when called, will add the Book – whose details the user has filled out – to the ObservableCollection in the main App class. Now, let’s move on to wiring up the button by opening the AddBookPage.xaml file and update the Button by adding an x:Name property:
x:Name="_addBookButton"
So the file should now look like this:
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyLibrary.AddBookPage" Title="Add Book"> <ContentPage.Content> <StackLayout Margin="10"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Grid.Column="0" Grid.Row="0" Text="Title"/> <Entry Grid.Column="1" Grid.Row="0" Placeholder="Title" Text="{Binding Book.Title}"/> <Label Grid.Column="0" Grid.Row="1" Text="Author"/> <Entry Grid.Column="1" Grid.Row="1" Placeholder="Author" Text="{Binding Book.Author}"/> <Label Grid.Column="0" Grid.Row="2" Text="ISBN"/> <Entry Grid.Column="1" Grid.Row="2" Placeholder="ISBN" Text="{Binding Book.ISBN}"/> </Grid> <Button x:Name="_addBookButton" Text="Add Book"/> </StackLayout> </ContentPage.Content> </ContentPage>
Now let’s open the AddBookPage.xaml.cs file and add the following text to the AddBookPage constructor:
_addBookButton.Clicked += (object sender, System.EventArgs e) => { ((AddBookPageViewModel)BindingContext).AddBook(); Navigation.PopAsync(); };
So the whole file should now look like this:
using Xamarin.Forms; namespace MyLibrary { public partial class AddBookPage : ContentPage { public AddBookPage() { InitializeComponent(); BindingContext = new AddBookPageViewModel(); _addBookButton.Clicked += (object sender, System.EventArgs e) => { ((AddBookPageViewModel)BindingContext).AddBook(); Navigation.PopAsync(); }; } } }
What we’ve done here is add a function to the Clicked EventHandler of the Button we named _addBookButton to call the AddBook function we added in the AddBookPageViewModel.cs file, followed by popping the page off the Navigation stack so we return to the Main Page.
Now, let’s click the ‘play’ button; if all went according to plan you should now be able to see a list of books, and add new ones using the Add Book page.