Xamarin.Forms is a UI framework that is built on top of Xamarin (for iOS and Android) and the Universal Windows Platform (UWP). Xamarin.Forms enables developers to create a UI for iOS, Android, and UWP with one shared code base, as illustrated in the following diagram. If we are building an application with Xamarin.Forms, we can use XAML, C#, or a combination of both to create the UI:
Xamarin.Forms is more or less just an abstract layer on top of each platform. Xamarin.Forms has a shared layer, which is used by all platforms, as well as a platform-specific layer. The platform-specific layer contains renderers. A renderer is a class that maps a Xamarin.Forms control into a platform-specific native control. Each Xamarin.Forms control has a platform-specific renderer.
The following diagram illustrates how an entry control in Xamarin.Forms is rendered to a UITextField control from the UIKit namespace when the shared Xamarin.Forms code is used in an iOS app. The same code in Android renders an EditText control from the Android.Widget namespace:
The most common way to declare your user interface in Xamarin.Forms is by defining it in a XAML document. It is also possible to create the GUI in C#, since XAML is really only a markup language for instantiating objects. You could, in theory, use XAML to create any type of object, as long as it has a parameterless constructor. A XAML document is an Extensible Markup Language (XML) document with a specific schema.
As a simple example, let's look at the following snippet of XAML:
<Label Text="Hello World!" />
When the XAML parser encounters this snippet, it will create an instance of a Label object and then set the properties of the object that correspond to the attributes in the XAML. This means that if we set a Text property in XAML, it will set the Text property on the instance of the Label object that is created. The XAML in the preceding example will have the same effect as the following:
var obj = new Label()
Text = "Hello World!"
XAML exists to make it easier to view the object hierarchy that you need to create in order to make a GUI. An object model for a GUI is also hierarchical by design, so XAML has support for adding child objects. You can simply add them as child nodes, as follows:
<Label Text="Hello World" />
<Entry Text="Ducks are us" />
The StackLayout is a container control that will organize the children vertically or horizontally within that container. A vertical organization is the default value, and will be used unless you specify otherwise. There are also a number of other containers, such as the Grid and the FlexLayout. These will be used in many of the projects in the following chapters.
A single control is no good unless it has a container that hosts it. Let's see what an entire page would look like. A fully valid ContentPage defined in XAML is an XML document. This means that we must start with an XML declaration. After that, we must have one, and only one, root node, as shown in the following code:
<?xml version="1.0" encoding="UTF-8"?>
<Label Text="Hello world!" />
In the preceding example, we have defined a ContentPage that translates into a single view on each platform. In order to make it valid XAML, you must specify a default namespace (xmlns="http://xamarin.com/schemas/2014/forms") and then add the x namespace (xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml").
The default namespace lets you create objects without prefixing them, like the StackLayout object. The x namespace lets you access properties such as the x:Class, which tells the XAML parser which class to instantiate to control the page when the ContentPage object is being created.
A ContentPage can have only one child. In this case, it's a StackLayout control. Unless you specify otherwise, the default layout orientation is vertical. A StackLayout can, therefore, have multiple children. Later on, we will touch on more advanced layout controls, such as the Grid and the FlexLayout control.
In this specific example, we are going to create a Label control as the first child of the StackLayout.
For clarity, the following code shows how the same thing would look in C#:
public class MainPage : ContentPage
A page is a class that inherits from the Xamarin.Forms.ContentPage. This class is autogenerated for you if you create a XAML page, but if you go code-only, then you will need to define it yourself.
Let's create the same control hierarchy as the XAML page we defined earlier using the following code:
var page = new MainPage();
var stacklayout = new StackLayout();
Text = "Welcome to Xamarin.Forms"
page.Content = stacklayout;
The first statement creates a page. You could, in theory, create a new page directly of the ContentPage type, but this would prohibit you from writing any code behind it. For this reason, it's a good practice to subclass each page that you are planning to create.
The block following this first statement creates the StackLayout control that contains the Label control that is added to the Children collection.
Finally, we need to assign the StackLayout to the Content property of the page.
Generally, using XAML will give you a much better overview, since the page is a hierarchical structure of objects and XAML is a very nice way of defining that structure. In code, the structure gets flipped around since you must define the innermost object first, making it harder to read the structure of your page. This was shown in an earlier example in this chapter. Having said that, it is generally a matter of preference as to how you decide to define the GUI. This book will use XAML rather than C# in the projects to come.
While this book is about Xamarin.Forms, we will highlight the difference between using traditional Xamarin and Xamarin.Forms. Traditional Xamarin is used when developing applications that use iOS and Android SDK without any means of abstraction. For example, we can create an iOS app that defines its user interface in a storyboard or in the code directly. This code will not be reusable for other platforms, such as Android. Applications built using this approach can still share non-platform-specific code by simply referencing a .NET standard library. This relationship is shown in the following diagram:
Xamarin.Forms, on the other hand, is an abstraction of the GUI, which allows us to define user interfaces in a platform-agnostic way. It still builds on top of Xamarin.iOS, Xamarin.Android, and all other supported platforms. The Xamarin.Forms application can be created as a .NET standard library or as a shared code project, where the source files are linked as copies and built within the same project as the platform you are currently building for. This relationship is shown in the following diagram:
Having said that, Xamarin.Forms cannot exist without traditional Xamarin, since it's bootstrapped through an application for each platform. This gives you the ability to extend Xamarin.Forms on each platform using custom renderers and platform-specific code that can be exposed to your shared code base through interfaces. We'll look at these concepts in detail later in this chapter.
We can use Xamarin.Forms in most cases and for most types of applications. If we need to use controls that not are available in Xamarin.Forms, we can always use the platform-specific APIs. There are, however, cases where Xamarin.Forms is not useful. The most common situation in which we might want to avoid using Xamarin.Forms is if we are building an app that we want to look very different across our target platforms.