commit 61fbfe251c2e39e5ab877c973bd17049935e6413
Author: mtoutant <martin.toutant@inrae.fr>
Date:   Fri Sep 30 14:50:19 2022 +0200

    Code ok - vérifier interface

diff --git a/BindableLayoutSample/BindableLayoutSample.Android/MainActivity.cs b/BindableLayoutSample/BindableLayoutSample.Android/MainActivity.cs
index ce5494b..e06fccb 100644
--- a/BindableLayoutSample/BindableLayoutSample.Android/MainActivity.cs
+++ b/BindableLayoutSample/BindableLayoutSample.Android/MainActivity.cs
@@ -1,5 +1,4 @@
-﻿using System;
-
+﻿
 using Android.App;
 using Android.Content.PM;
 using Android.Runtime;
diff --git a/BindableLayoutSample/BindableLayoutSample.Android/Properties/AssemblyInfo.cs b/BindableLayoutSample/BindableLayoutSample.Android/Properties/AssemblyInfo.cs
index 5bb81ec..33503d2 100644
--- a/BindableLayoutSample/BindableLayoutSample.Android/Properties/AssemblyInfo.cs
+++ b/BindableLayoutSample/BindableLayoutSample.Android/Properties/AssemblyInfo.cs
@@ -1,5 +1,4 @@
 ﻿using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using Android.App;
 
diff --git a/BindableLayoutSample/BindableLayoutSample/App.xaml.cs b/BindableLayoutSample/BindableLayoutSample/App.xaml.cs
index 5f409f7..82f5893 100644
--- a/BindableLayoutSample/BindableLayoutSample/App.xaml.cs
+++ b/BindableLayoutSample/BindableLayoutSample/App.xaml.cs
@@ -1,7 +1,5 @@
 ﻿using BindableLayoutSample.View;
-using System;
 using Xamarin.Forms;
-using Xamarin.Forms.Xaml;
 
 namespace BindableLayoutSample
 {
@@ -11,7 +9,8 @@ namespace BindableLayoutSample
         {
             InitializeComponent();
 
-            MainPage = new AnimalListView();
+            // Point d'entrée de l'application
+            MainPage = new NavigationPage(new AnimalListView());
         }
 
         protected override void OnStart()
diff --git a/BindableLayoutSample/BindableLayoutSample/DAO/AnimalDAO.cs b/BindableLayoutSample/BindableLayoutSample/DAO/AnimalDAO.cs
index f67da42..5c3f272 100644
--- a/BindableLayoutSample/BindableLayoutSample/DAO/AnimalDAO.cs
+++ b/BindableLayoutSample/BindableLayoutSample/DAO/AnimalDAO.cs
@@ -1,15 +1,16 @@
 ﻿using BindableLayoutSample.Model;
 using System;
 using System.Collections.Generic;
-using System.Text;
 using System.Threading.Tasks;
 
 namespace BindableLayoutSample.DAO
 {
+    // La classe d'accès aux données sur les animaux
     public class AnimalDAO
     {
         public async Task<List<Animal>> GetAllAnimals()
         {
+            // Génération de fausse données
             List<Animal> ret = new List<Animal>()
             {
                 new Animal()
@@ -45,7 +46,7 @@ namespace BindableLayoutSample.DAO
             };
 
             // Simulation d'attente d'accès aux données (WS, BDD, ...)
-            await Task.Delay(500);
+            await Task.Delay(1000);
             return ret;
         }
     }
diff --git a/BindableLayoutSample/BindableLayoutSample/MainPage.xaml.cs b/BindableLayoutSample/BindableLayoutSample/MainPage.xaml.cs
index a1674ca..4cbb3d9 100644
--- a/BindableLayoutSample/BindableLayoutSample/MainPage.xaml.cs
+++ b/BindableLayoutSample/BindableLayoutSample/MainPage.xaml.cs
@@ -1,10 +1,4 @@
-﻿using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xamarin.Forms;
+﻿using Xamarin.Forms;
 
 namespace BindableLayoutSample
 {
diff --git a/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs b/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
index 9f02075..30924e2 100644
--- a/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
+++ b/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
@@ -1,9 +1,8 @@
 ﻿using System;
-using System.Collections.Generic;
-using System.Text;
 
 namespace BindableLayoutSample.Model
 {
+    // Le modèle Animal avec ses 3 propriétés et accesseurs
     public class Animal
     {
         public int AnimalID { get; set; }
diff --git a/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml b/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml
index df94f65..e6ba913 100644
--- a/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml
+++ b/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml
@@ -4,11 +4,30 @@
     xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
     <ContentPage.Content>
-        <StackLayout>
+        <StackLayout Spacing="30" VerticalOptions="CenterAndExpand">
+            <!--  Les infos de l'animal  -->
             <Label
+                FontAttributes="Bold"
+                FontSize="25"
                 HorizontalOptions="CenterAndExpand"
-                Text="!"
-                VerticalOptions="CenterAndExpand" />
+                Text="{Binding Animal.AnimalID, StringFormat='Animal n° {0}'}"
+                TextColor="DarkCyan" />
+            <Label
+                FontAttributes="Italic"
+                FontSize="20"
+                HorizontalOptions="CenterAndExpand"
+                Text="{Binding Animal.Elevage, StringFormat='Elevage: {0}'}"
+                TextColor="DarkGray" />
+            <!--
+                L'enchainement &#..; permet d'avoir une chaine de code éxecutable
+                dans une chaine de caractère, ici cela permet de créer un retour à la ligne
+            -->
+            <Label
+                FontSize="18"
+                HorizontalOptions="CenterAndExpand"
+                HorizontalTextAlignment="Center"
+                Text="{Binding Animal.DateTraitement, StringFormat='Date du dernier traitement:&#10; {0:ddd dd MMMM yyyy}'}"
+                TextColor="Black" />
         </StackLayout>
     </ContentPage.Content>
 </ContentPage>
\ No newline at end of file
diff --git a/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml.cs b/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml.cs
index bb18979..30cbf7b 100644
--- a/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml.cs
+++ b/BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml.cs
@@ -1,9 +1,5 @@
-﻿using BindableLayoutSample.ViewModel;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+﻿using BindableLayoutSample.Model;
+using BindableLayoutSample.ViewModel;
 
 using Xamarin.Forms;
 using Xamarin.Forms.Xaml;
@@ -13,10 +9,10 @@ namespace BindableLayoutSample.View
     [XamlCompilation(XamlCompilationOptions.Compile)]
     public partial class AnimalDetailsView : ContentPage
     {
-        public AnimalDetailsView()
+        public AnimalDetailsView(Animal animal)
         {
             InitializeComponent();
-            BindingContext = new AnimalDetailsViewModel();
+            BindingContext = new AnimalDetailsViewModel(animal);
         }
     }
 }
\ No newline at end of file
diff --git a/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml b/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
index 12628ac..17f1746 100644
--- a/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
+++ b/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
@@ -3,16 +3,127 @@
     x:Class="BindableLayoutSample.View.AnimalListView"
     xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
-    xmlns:xe="clr-namespace:XamEffects;assembly=XamEffects">
+    xmlns:xe="clr-namespace:XamEffects;assembly=XamEffects"
+    Title="BindableLayout Sample App">
     <ContentPage.Content>
-        <StackLayout>
-            <Label
+        <Grid>
+            <StackLayout
+                Padding="60,10"
                 HorizontalOptions="CenterAndExpand"
-                Text="Animal List"
-                VerticalOptions="CenterAndExpand" />
-            <xe:BorderView xe:TouchEffect.Color="LightBlue" BackgroundColor="#4b6da6">
-                <Label FontAttributes="Bold" Text="Load animals" />
-            </xe:BorderView>
-        </StackLayout>
+                VerticalOptions="CenterAndExpand">
+                <StackLayout>
+                    <Label
+                        FontSize="Medium"
+                        HorizontalTextAlignment="Center"
+                        Text="Animal list" />
+                    <!--  Une border view de XamEffects est plus sympa qu'un bouton par défault  -->
+                    <xe:BorderView
+                        xe:Commands.Tap="{Binding LoadAnimalsCommand}"
+                        xe:TouchEffect.Color="LightBlue"
+                        BackgroundColor="#4b6da6"
+                        CornerRadius="20"
+                        HorizontalOptions="Center">
+                        <Label
+                            Margin="15,10"
+                            FontAttributes="Bold"
+                            Text="Load animals"
+                            TextColor="White" />
+                    </xe:BorderView>
+                </StackLayout>
+
+                <!--  La Frame est visible seulement si les animaux ont été chargés  -->
+                <Frame
+                    Padding="0,10,0,0"
+                    BackgroundColor="Transparent"
+                    BorderColor="#4b6da6"
+                    CornerRadius="20"
+                    HasShadow="False"
+                    IsVisible="{Binding IsLoadedAnimals}">
+                    <StackLayout Spacing="0">
+                        <Grid ColumnDefinitions="*,2*">
+                            <Label
+                                Grid.Row="0"
+                                Grid.Column="0"
+                                FontAttributes="Bold"
+                                HorizontalOptions="CenterAndExpand"
+                                Text="ID"
+                                TextColor="DarkCyan"
+                                VerticalOptions="CenterAndExpand" />
+                            <Label
+                                Grid.Row="0"
+                                Grid.Column="1"
+                                FontSize="Medium"
+                                HorizontalOptions="CenterAndExpand"
+                                Text="Elevage"
+                                TextColor="DarkGray" />
+                        </Grid>
+                        <BoxView
+                            Margin="0,10,0,0"
+                            HeightRequest="1"
+                            HorizontalOptions="FillAndExpand"
+                            Color="#4b6da6" />
+                        <!--
+                            On utilise une scroll view au cas ou beaucoup d'animaux sont chargés
+                            On assure qu'ils soient tous accessible si la taille de la liste venait
+                            à dépasser la taille de l'écran
+                        -->
+                        <ScrollView>
+                            <StackLayout Padding="0,5" BindableLayout.ItemsSource="{Binding AnimalList}">
+                                <!--
+                                    On entre dans une itération sur BindableLayout.ItemSource donc AnimalList
+                                -->
+                                <BindableLayout.ItemTemplate>
+                                    <!--
+                                        Dans le dataTemplate, le BindingContext est lié à l'AnimalItemViewModel
+                                        de l'itération
+                                    -->
+                                    <DataTemplate>
+                                        <!--
+                                            Lors du "tap", on utilise la commande de navigation définie
+                                            dans AnimalItemViewModel
+                                        -->
+                                        <Grid
+                                            Padding="5"
+                                            xe:Commands.Tap="{Binding NavigateToAnimalCommand}"
+                                            xe:TouchEffect.Color="#4b6da6"
+                                            ColumnDefinitions="*,2*"
+                                            RowDefinitions="Auto, Auto"
+                                            RowSpacing="0">
+                                            <!--
+                                                Les infos qu'on cherche se trouve dans l'objet Animal de
+                                                AnimalItemViewModel
+                                            -->
+                                            <Label
+                                                Grid.Row="0"
+                                                Grid.Column="0"
+                                                FontAttributes="Bold"
+                                                HorizontalOptions="CenterAndExpand"
+                                                Text="{Binding Animal.AnimalID}"
+                                                TextColor="DarkCyan"
+                                                VerticalOptions="CenterAndExpand" />
+                                            <Label
+                                                Grid.Row="0"
+                                                Grid.Column="1"
+                                                FontSize="Medium"
+                                                HorizontalOptions="CenterAndExpand"
+                                                Text="{Binding Animal.Elevage}"
+                                                TextColor="DarkGray" />
+                                        </Grid>
+                                    </DataTemplate>
+                                </BindableLayout.ItemTemplate>
+                            </StackLayout>
+                        </ScrollView>
+                    </StackLayout>
+                </Frame>
+            </StackLayout>
+            <!--  Indicateur de travail en cours  -->
+            <Grid Grid.RowSpan="1" IsVisible="{Binding IsBusy}">
+                <BoxView BackgroundColor="White" Opacity="0.4" />
+                <ActivityIndicator
+                    HorizontalOptions="Center"
+                    IsRunning="True"
+                    Color="Green" />
+            </Grid>
+        </Grid>
     </ContentPage.Content>
 </ContentPage>
\ No newline at end of file
diff --git a/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml.cs b/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml.cs
index 5a0329d..ce1c945 100644
--- a/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml.cs
+++ b/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml.cs
@@ -1,10 +1,4 @@
 ﻿using BindableLayoutSample.ViewModel;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
 using Xamarin.Forms;
 using Xamarin.Forms.Xaml;
 
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalDetailsViewModel.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalDetailsViewModel.cs
index f588ba6..a61ffc0 100644
--- a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalDetailsViewModel.cs
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalDetailsViewModel.cs
@@ -1,10 +1,23 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Text;
+﻿using BindableLayoutSample.Model;
+using BindableLayoutSample.ViewModel.Base;
 
 namespace BindableLayoutSample.ViewModel
 {
-    public class AnimalDetailsViewModel
+    // Le ViewModel de la page d'information sur chaque animal
+    // Instancié avec un objet de type Animal passé en argument
+    public class AnimalDetailsViewModel : ViewModelBase
     {
+        private Animal animal;
+
+        public Animal Animal
+        {
+            get => animal;
+            set => SetProperty(ref animal, value);
+        }
+
+        public AnimalDetailsViewModel(Animal _animal)
+        {
+            Animal = _animal;
+        }
     }
 }
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
index 96907e2..d08957b 100644
--- a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
@@ -1,10 +1,42 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Text;
+﻿using BindableLayoutSample.Model;
+using BindableLayoutSample.View;
+using BindableLayoutSample.ViewModel.Base;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using Xamarin.Forms;
 
 namespace BindableLayoutSample.ViewModel
 {
-    public class AnimalItemViewModel
+    public class AnimalItemViewModel : ViewModelBase
     {
+        private Animal animal;
+
+        // Les infos de l'animal
+        public Animal Animal
+        {
+            get => animal;
+            set => SetProperty(ref animal, value);
+        }
+
+        // La commande de navigation est asynchrone,
+        // Pour ne pas bloquer le Thread principal en charge de l'affichage
+        // pendant l'instanciation de la nouvelle Page
+        private async Task NavigateToAnimalDetails()
+        {
+            // Petite attente pour rendre la transition plus fluide
+            await Task.Delay(150);
+
+            // L'utilisation de la navigation page nous permet d'avoir une navigation verticale (push & pop)
+            await Application.Current.MainPage.Navigation.PushAsync(new AnimalDetailsView(Animal));
+        }
+
+        public ICommand NavigateToAnimalCommand { private set; get; }
+
+        public AnimalItemViewModel(Animal _animal)
+        {
+            Animal = _animal;
+            NavigateToAnimalCommand = new Command(async () => await NavigateToAnimalDetails());
+        }
+
     }
 }
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
index bb3dac0..0c361a1 100644
--- a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
@@ -1,10 +1,79 @@
-﻿using System;
+﻿using BindableLayoutSample.DAO;
+using BindableLayoutSample.Model;
+using BindableLayoutSample.ViewModel.Base;
 using System.Collections.Generic;
-using System.Text;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using Xamarin.Forms;
 
 namespace BindableLayoutSample.ViewModel
 {
-    public class AnimalListViewModel
+    // Le ViewModel de la page d'affichage de la liste d'animaux
+    public class AnimalListViewModel : ViewModelBase
     {
+        #region Attributes
+
+        private bool isBusy;
+        private bool isLoadedAnimals;
+
+        #endregion
+
+        #region Properties
+        // Indicateur de travail en cours
+        public bool IsBusy
+        {
+            get => isBusy;
+            set => SetProperty(ref isBusy, value);
+        }
+
+        // Indicateur sur l'état de chargement des données animaux
+        public bool IsLoadedAnimals
+        {
+            get => isLoadedAnimals;
+            set => SetProperty(ref isLoadedAnimals, value);
+        }
+
+        // La liste d'animaux qui sera alimentée avec les données récupérées par la DAO
+        // L'objet ObservableCollection implémente directement INPC
+        public ObservableCollection<AnimalItemViewModel> AnimalList { get; set; }
+
+        #endregion
+
+        #region Commands
+        // La commande de chargement des données animaux
+        // Asynchrone pour ne pas bloquer le thread principal
+        // et donc pour ne pas bloquer l'affichage
+        private async Task LoadAnimalCommand()
+        {
+            IsBusy = true;
+            IsLoadedAnimals = false;
+            AnimalList.Clear();
+
+            AnimalDAO dao = new AnimalDAO();
+            List<Animal> result = await dao.GetAllAnimals();
+            
+            // On alimente la liste observée par la view (AnimalList)
+            foreach (Animal _animal in result)
+            {
+                AnimalItemViewModel toAddItem = new AnimalItemViewModel(_animal);
+                AnimalList.Add(toAddItem);
+            }
+
+            IsLoadedAnimals = true;
+            IsBusy = false;
+        }
+
+        public ICommand LoadAnimalsCommand { private set; get; }
+        #endregion 
+        
+        // CTOR
+        public AnimalListViewModel()
+        {
+            // Il important d'initialiser les listes d'un ViewModel pour éviter
+            // les NullPointerExceptions
+            AnimalList = new ObservableCollection<AnimalItemViewModel>();
+            LoadAnimalsCommand = new Command(async () => await LoadAnimalCommand());
+        }
     }
 }
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs
new file mode 100644
index 0000000..3c4c795
--- /dev/null
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs
@@ -0,0 +1,39 @@
+﻿using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace BindableLayoutSample.ViewModel.Base
+{
+    public class ViewModelBase : INotifyPropertyChanged
+    {
+        // Propriété de notification de changement
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        // Procédure de changement de valeur
+        // Déclenche la fonction de notification
+        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyname = null)
+        {
+            if (Equals(storage, value))
+            {
+                return false;
+            }
+
+            storage = value;
+            OnPropertyChanged(propertyname);
+            return true;
+        }
+
+        // Fonction de notification 
+        // Déclenche l'évènement de changement de valeur
+        // Avec en argument le nom de la propriété qui a changé
+        protected void OnPropertyChanged(string propertyName)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+
+        public ViewModelBase()
+        {
+
+        }
+
+    }
+}
