Skip to content

Lesson3

Jia Ming edited this page Nov 17, 2018 · 16 revisions

Table of Contents

  1. Creating a project
  2. Basic XAML
  3. Data Binding
  4. MVVM Basics

Creating a project

Go to File -> New -> New Project

Select Cross-Platform

Select Mobile App(Xamarin.Forms) image

Note: In case you cannot see Xamarin.Forms option you can go Visual Studio Installer and install .NET Mobile Development

You should see something like this in Solution Explorer.

image

It is fine if you don't have the UWP project, although it is recommended to have, because building and running UWP is fastest, but Windows only.

Basic XAML

Extensible Application Markup Language (XAML) is a declarative XML-based language developed by Microsoft that is used for initializing structured values and objects.

Read through the tutorial here: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/

Tips

You can look through all the possible options when looking through Visual Studio's suggestions, as seen below. image

You can preview your UI when you are doing the design image

Examples

StackLayout

Considered a container. Able to keep adding elements, will order elements sequentially.

Example of 2 Labels inside a StackLayout

<StackLayout>
    <Label Text="Welcome to Xamarin.Forms!" 
        HorizontalOptions="Center"
        VerticalOptions="CenterAndExpand" />
    <Label Text="HELLO"
            FontSize="Large"
            HorizontalOptions="Center"
            VerticalOptions="CenterAndExpand" />
</StackLayout>

Grid

Also another container. Much more controllable than StackLayout, can adjust rows and heights based on screen size, absolute size, or child element size.

Only way to add row is to add RowDefinition, column then ColumnDefinition Example of a 3x3 Grid

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="100" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="100" />
    </Grid.ColumnDefinitions>
    ...
</Grid>

Height/Width Definitions


1. Auto

Resizes based on child element in the row/column, i.e. if child element is 60px wide then the row will be 60px wide

2. *

Takes up the rest of the space in the row/column

3. <Some number>

Takes up number of pixels according to the specified number


Special case: Multiple rows/columns with *

<Grid.RowDefinitions>
    <RowDefinition Height="3*" />
    <RowDefinition Height="*" />
    <RowDefinition Height="100" />
</Grid.RowDefinitions>

In this case 100 pixels will be first allocated to the 3rd row. Then for the remaining space, 75% goes to 1st row, 25% goes to 2nd row


Assigning Child to Cell

XAML uses 0 indexing, meaning the example below is assigned to the cell in row 2 column 2.

<Entry Grid.Row="1" Grid.Column="1"
        Text="{Binding StudentId}"/>

Practice

Design something like this using grid

image

Quick Note:

When doing the exercise, you will find that vistual studio will actually give you some suggestion on what to auto-complete. Here is an example of what I'm talking about: image

You can read up on every single of the element/property that XamarinForms provide in the XamarinForms Documentations

The documentation shows both the implementation of the UI element in XAML and C#.

This is the solution

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="50" />
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Label Grid.Row="0"
            Grid.Column="0"
            Text="Name" 
            Margin="5"
            HorizontalTextAlignment="End"
            HorizontalOptions="Center"
            VerticalTextAlignment="Center" />

    <Entry Grid.Row="0" Grid.Column="1"
            Text="{Binding Name}"/>

    <Label Grid.Row="1"
            Grid.Column="0"
            Text="Student ID" 
            Margin="5"
            HorizontalTextAlignment="End"
            HorizontalOptions="Center"
            VerticalTextAlignment="Center" />
    <Entry Grid.Row="1" Grid.Column="1"
            Text="{Binding StudentId}"/>

    <Label Grid.Row="2"
            Grid.Column="0"
            Text="Email" 
            Margin="5"
            HorizontalTextAlignment="End"
            HorizontalOptions="Center"
            VerticalTextAlignment="Center" />
    <Entry Grid.Row="2" Grid.Column="1"
            Text="{Binding Email}" />

    <Button Grid.Row="3"
            Grid.Column="0"
            Grid.ColumnSpan="2"
            VerticalOptions="End"
            Text="Submit" />
</Grid>

Data Binding

Data binding basically binds the UI with some data storage class, in this case normally the ViewModel. This allows us to completely separate the data from the UI. We can also separate a lot of UI logic from the UI itself, such as the function that is ran when a button is clicked.

Through this, because most of our data and logic no longer relies on the UI, we can easily swap out the UI display, and we can easily test most of our logic without a UI. With the use of automated testing, we can save a lot of time testing the UI logic.

Moreover it also makes code management simple, as the person in charge of UI styling doesn't need to care anything about where each data goes and so on.

1. Add a new class

image

Name it MainViewModel

image

2. Edit the class

i) Make the class public

ii) Add a few public properties

public class MainViewModel
{
    public string Name { get; set; }
    public string StudentId { get; set; }
    public string Email { get; set; }
}

Note: It has to be properties for the binding to work, property has the "get set" while fields don't

3. Instantiate the class

Go to MainPage.xaml.cs

In the constructor of MainPage, instantiate a MainViewModel object, and assign it to the BindingContext property

public MainPage()
{
    InitializeComponent();
    BindingContext = new MainViewModel();
}

MainPage is a partial class because the definition of the class is split into 2 parts, 1 part in the .xaml and 1 part in the .cs file. Although they seem different and intuitively they can't combine, just know that the .xaml file will be compiled into the same intermediate language that the .cs file will be compiled into, and this is how the .xaml and .cs file is combined into 1. This also means that any variable you declare in the xaml file can be accessed in the .cs file and vice versa.

To access UI element in the .cs file, you will need to give a name/identifier to the element. In this case, the grid element is given a name/identifier of "mainGrid": .xaml part

<Grid x:Name="mainGrid">
   ....
</Grid>

Now you can access the grid in the .cs part also known as the Code Behind.

You can add elements directly to the grid using the name/identifier like so in the .cs part

mainGrid.Children.Add(new Label() { Text = "HELLO" });

4. Bind the property from the XAML code

<Entry Grid.Row="0" Grid.Column="1"
       Text="{Binding Name}"/>

5. Create a function to print the data

In MainViewModel.cs Add a function to print data e.g.

private void Print()
{
    Debug.WriteLine($"Name: {Name}");
    Debug.WriteLine($"StudentId: {StudentId}");
    Debug.WriteLine($"Email: {Email}");
}

6. Create a wrapper for this function

This is called a Command, can be used to bind to a button. You cannot bind a function to a button. Also in MainViewModel.cs

public ICommand ClickCommand {
    get { return new Xamarin.Forms.Command(Print); }
}

7. Bind this function to the button

<Button Text="Submit" 
        Command="{Binding ClickCommand}"/>

8. Run the application in Debug mode

For an android app that looks like this

image

Press the submit button.

Open the output window image

Data binding works now

MVVM Basics

The Model-View-ViewModel (MVVM) architectural pattern was invented with XAML in mind. The pattern enforces a separation between three software layers.

  1. the XAML user interface, called the View
  2. Underlying data model, called the Model
  3. An intermediary between the View and the Model, called the ViewModel

The View and the ViewModel are often connected through data bindings defined in the XAML file. The BindingContext for the View is usually an instance of the ViewModel

Note that there is also another very important layer, called Services. This is where most of the logic is handled, such as sending data to server or reading data from server.

In a very pure MVVM context, the ViewModel is only in charge of handling any data that directly deals with the UI, it has no responsibility on anything else, such as data processing. Moreover, in this context, it is necessary for the ViewModel to be able to run in a headless mode (i.e. without UI), such that UI logic can be tested without wasting time launching UI.