Skip to content

12 Xamarin

Xamarin

  • Abstraction layer that manages communication of shared code with underlying platform code.
  • Runs in a managed environment that provides conveniences such as memory allocation and garbage collection.
  • Open-source platform for building modern and performant applications for iOS, Android, Windows and Mac.

Share code and business logic across platforms.

xamarin

Code sharing

  • Enables developers to share an average of 90% of their application code across platforms
  • Achieve native performance, look, and feel on each platform.
  • Can be written on PC or Mac and compile into native application packages, such as an .apk file on Android, or an .ipa file on iOS.
  • Officially requires Win and or Mac for development (Mac is mandatory for iOS development) and Visual Studio or Visual Studio - Mac. Rider is also an option, theoretically Android should be doable under Linux.

Xamarin overview

xamarin

Xamarin how it works

xamarin

Android

  • Xamarin.Android applications compile from C# into Intermediate Language (IL) which is then Just-in-Time (JIT) compiled to a native assembly when the application launches.
  • Xamarin.Android applications run within the Mono execution environment, side by side with the Android Runtime (ART) virtual machine.
  • Mono execution environment calls into Android/Java via Managed Callable Wrappers (MCW) and provides Android Callable Wrappers (ACW) to the ART

iOS

  • Xamarin.iOS applications are fully Ahead-of-Time (AOT) compiled from C# into native ARM assembly code.
  • Xamarin uses Selectors to expose Objective-C to managed C# and Registrars to expose managed C# code to Objective-C.
  • Selectors and Registrars collectively are called "bindings" and allow Objective-C and C# to communicate.

Xamarin.Forms and MAUI

  • Complete cross-platform UI toolkit for .NET
  • Create user interfaces in XAML with code-behind in C#. Rendered as performant native controls.

.NET MAUI

Since .NET MAUI is an evolution of Xamarin.Forms, they have most of their features in common. You can get almost all things in .NET MAUI that Xamarin has, like controls, layouts, Shell, gestures, templates, and cross-platform APIs for device features. You can find all these in .NET MAUI with a different namespace.

xamarin xamarin

Xamarin.Forms vs Xamarin.Native

Xamarin-Forms

  • Application that requires little platform-specific functionality, where code sharing is more important than custom UI

Xamarin.Native (iOS and Android)

  • Cross-platform apps with intricate designs, specialized user interactions, and platform-specific APIs
  • iOS – stroryboards, Android – AXML, UWP – XAML

First App

What IDE to use?

  • Visual Studio is the native one - both on mac and windows.
  • Rider has some limitations.
  • https://visualstudio.microsoft.com/vs/mac/
  • Start with Xamarin.Forms

First App - Rider vs VS Mac

xamarin xamarin

First App - Forms

Shared project

  • All shared UI and BLL logic

Platform specific projects

  • App.Android – almost native like structure
    • Layout folder does not contain your UI
    • MainActivity.cs calls into App.xaml.cs to start up
  • App.iOS – almost native like structure
    • AppDelegate.cs initializes Xamarin.Forms and call into shared App project to start up
    • Info.plist and Entitlements.plist – app information and needed device features

UI 1 (xaml)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?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:App"
             x:Class="App.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin.Forms!"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>

</ContentPage>

UI 2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<ContentPage >
    <StackLayout VerticalOptions="Center">
        <Label Text="0"
               x:Name="CounterLabel"
               TextColor="Aquamarine"
               FontSize="72"
               FontFamily="ComicSans"
               HorizontalOptions="Center"  />
        <Button Text="Increment!"
                Clicked="IncrementCounterClicked"
                FontSize="46" />
    </StackLayout>
</ContentPage>

xamarin xamarin

First App - code

MainPage.xaml.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
using Xamarin.Forms;

namespace App
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public partial class MainPage : ContentPage
{
    private int _count = 0;

    public MainPage()
    {
        InitializeComponent();
    }

    private void IncrementCounterClicked(object sender, EventArgs e)
    {
        _count++;
        CounterLabel.Text = _count.ToString();
    }
}

CSS

Create styles.css

1
2
3
4
5
6
7
8
label {
    font-size: 72;
    color: aquamarine;
}

button {
    font-size: 46;
}

Use in xaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<ContentPage  x:Class="App.MainPage">

    <ContentPage.Resources>
        <StyleSheet Source="/styles.css" />
    </ContentPage.Resources>

    <StackLayout VerticalOptions="Center">
        <Label Text="0"
               x:Name="CounterLabel"
               HorizontalOptions="Center" />

        <Button Text="Increment!"
                Clicked="IncrementCounterClicked" />

    </StackLayout>

</ContentPage>

Data Binding

  • Data binding is used to simplify how a Xamarin.Forms application displays and interacts with its data.
  • It establishes a connection between the user interface and the underlying application.

xamarin

  • While the BindingContext property of each target object can be individually set, this isn’t necessary. BindingContext is a special property that’s inherited by all its children.

  • Data bindings connect properties of two objects, called the source and the target.

  • In code, two steps are required: The BindingContext property of the target object must be set to the source object, and the SetBinding method (often used in conjunction with the Binding class) must be called on the target object to bind a property of that object to a property of the source object.

BindingContext

Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.

1
2
3
4
var label = new Label (); 
label.SetBinding (Label.TextProperty, "Name"); 
label.BindingContext = new {Name = "John Doe", Company = "Xamarin"}; 
Debug.WriteLine (label.Text); //prints "John Doe"

Typically, the runtime performance is better if BindingContext is set after all calls to SetBinding(BindableProperty, BindingBase) have been made.

Data binding to self/view

  • ViewModels generally implement the INotifyPropertyChanged interface, which means that the class fires a PropertyChanged event whenever one of its properties changes.

  • ContentPage and others already implement INotifyPropertyChanged

1
public partial class MainPage : ContentPage //, INotifyPropertyChanged

Data binding to view

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:testMaui001="clr-namespace:TestMaui001"
             x:Class="TestMaui001.MainPage"
             x:DataType="testMaui001:MainPage">

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">
            <Label 
                x:Name="LabelCounter"
                Text="{Binding  Count}"
                TextColor="Aquamarine"
                FontSize="72"
                FontFamily="ComicSans"
                HorizontalOptions="Center"
                   />
            <Button
                x:Name="CounterBtn"
                Text="Click me"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
namespace TestMaui001;

public partial class MainPage : ContentPage
{
    private int _count;

    public int Count
    {
        get => _count;
        set
        {
            if (value == _count) return;
            _count = value;
            OnPropertyChanged();
        }
    }

    public MainPage()
    {
        InitializeComponent();
        BindingContext = this;
    }

    private void OnCounterClicked(object sender, EventArgs e)
    {
        Count++;
    }
}

Data binding, MVVM

Model-View-ViewModel

  • The view is responsible for defining the structure, layout, and appearance of what the user sees on screen.
  • The view model implements properties and commands to which the view can data bind to, and notifies the view of any state changes through change notification events.
  • Model classes are non-visual classes that encapsulate the app's data. Data model, business and validation logic, repos, etc.

xamarin

MVVM - ViewModel

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainPageVM : INotifyPropertyChanged
{
    private int _count;

    public int Count
    {
        get => _count;
        set
        {
            if (value == _count) return;
            _count = value;
            OnPropertyChanged();
        }
    }

    // ===================      INotifyPropertyChanged       ======================

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

MVVM, View (with code)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:testMaui001="clr-namespace:TestMaui001"
             x:Class="TestMaui001.MainPage"
             x:DataType="testMaui001:MainPageVM">

    <ContentPage.BindingContext>
        <testMaui001:MainPageVM />
    </ContentPage.BindingContext>

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">
            <Label 
                x:Name="LabelCounter"
                Text="{Binding  Count}"
                TextColor="Aquamarine"
                FontSize="72"
                FontFamily="ComicSans"
                HorizontalOptions="Center"
                   />
            <Button
                x:Name="CounterBtn"
                Text="Click me"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
namespace TestMaui001;

public partial class MainPage : ContentPage
{

    public MainPage() =>
        InitializeComponent();

    private void OnCounterClicked(object sender, EventArgs e)
    {
        ((MainPageVM) this.BindingContext).Count++;
    }
}

MVVM, ViewModel

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MainPageVM : INotifyPropertyChanged
{
    public ICommand IncrementCounter { get; protected set; }

    public MainPageVM()
    {
        IncrementCounter = new Command(() => Counter++);
    }

    private int _counter;
    public int Counter
    {
        get => _counter;
        set
        {
            _counter = value;
            OnPropertyChanged(nameof(Counter));
        }
    }
    // ====================== INotifyPropertyChanged ==============================
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
1
2
3
<Button
    Text="Increment"
    Command="{Binding IncrementCounter}" />
1
2
3
4
public partial class MainPage : ContentPage
{
    public MainPage() => InitializeComponent();
}

MVVM, binding in xaml

1
2
3
4
5
6
7
8
public class MainPageVM : INotifyPropertyChanged
{
    public ICommand IncrementByParam { get; set; }

    public MainPageVM()
    {
          IncrementByParam = new Command((no) => Counter += int.Parse((string)no));
    }
1
2
3
4
5
6
<Editor x:Name="EditBox" Text="5"/>
<Button
    Text="Increment by edit box"
    Command="{Binding IncrementByParam}"
    CommandParameter="{Binding Source={x:Reference EditBox}, Path=Text}"
/>

listview

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public ObservableCollection<ListItem> MyList { get; set; } = new ObservableCollection<ListItem>();

private int _counter;
public int Counter
{
    get => _counter;
    set
    {
        _counter = value;
        MyList.Add(new ListItem()
        {
            Value = value.ToString(),
            DT = DateTime.Now.ToString()
        });
        OnPropertyChanged(nameof(Counter));
    }
}
1
2
3
4
5
public class ListItem
{
    public string Value { get; set; }
    public string DT { get; set; }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<ListView ItemsSource="{Binding MyList}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout Orientation="Vertical">
                    <StackLayout Orientation="Horizontal">
                        <Label
                            Text="{Binding Value}"
                            FontSize="30"
                            TextColor="Chartreuse" />
                        <Label
                            Text="{Binding DT}"
                            FontSize="20"
                            TextColor="Chocolate" />
                    </StackLayout>
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>