commit a08e96d32f1d7060fd6dd127ac6e3195b48e2218
Author: mtoutant <martin.toutant@inrae.fr>
Date:   Fri Oct 7 09:36:49 2022 +0200

    dernier commit, migration vers GitLab de la forgeMIA, ce repo ne sera pas mis à jour

diff --git a/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs b/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
index 30924e2..970f6c7 100644
--- a/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
+++ b/BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
@@ -8,5 +8,6 @@ namespace BindableLayoutSample.Model
         public int AnimalID { get; set; }
         public string Elevage { get; set; }
         public DateTime DateTraitement { get; set; }
+
     }
 }
diff --git a/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml b/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
index 17f1746..ecbe86c 100644
--- a/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
+++ b/BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
@@ -93,6 +93,7 @@
                                                 Les infos qu'on cherche se trouve dans l'objet Animal de
                                                 AnimalItemViewModel
                                             -->
+                                            <Label Text="Bonjour" />
                                             <Label
                                                 Grid.Row="0"
                                                 Grid.Column="0"
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
index d08957b..8554b08 100644
--- a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
@@ -38,5 +38,10 @@ namespace BindableLayoutSample.ViewModel
             NavigateToAnimalCommand = new Command(async () => await NavigateToAnimalDetails());
         }
 
+        public override string ToString()
+        {
+            return "" + Animal.AnimalID;
+        }
+
     }
 }
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
index 0c361a1..64b891e 100644
--- a/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
@@ -13,10 +13,8 @@ namespace BindableLayoutSample.ViewModel
     public class AnimalListViewModel : ViewModelBase
     {
         #region Attributes
-
         private bool isBusy;
         private bool isLoadedAnimals;
-
         #endregion
 
         #region Properties
@@ -37,7 +35,6 @@ namespace BindableLayoutSample.ViewModel
         // 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
diff --git a/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs b/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs
index 3c4c795..34b0ae3 100644
--- a/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs
+++ b/BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs
@@ -29,11 +29,5 @@ namespace BindableLayoutSample.ViewModel.Base
         {
             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
         }
-
-        public ViewModelBase()
-        {
-
-        }
-
     }
 }
diff --git a/Wiki.md b/Wiki.md
new file mode 100644
index 0000000..ad2bb77
--- /dev/null
+++ b/Wiki.md
@@ -0,0 +1,307 @@
+---
+title: "Tuto BindableLayout - Wiki"
+---
+
+## Objectif
+
+L’objectif de ce tutoriel est de se familiariser avec l’élément BindableLayout pour afficher, avec beaucoup de liberté, les éléments d’une liste. 
+Au cours de ce tutoriel nous allons créer l’interface suivante:
+!Resultat_700.png!
+
+Nous allons travailler avec le modèle Animal suivant :
+
+```csharp
+// Le modèle Animal avec ses 3 propriétés et accesseurs
+public class Animal
+{
+    public int AnimalID { get; set; }
+    public string Elevage { get; set; }
+    public DateTime DateTraitement { get; set; }
+}
+```
+
+La première page affiche cette liste d’animaux avec l’id et l’élevage, et lors du _tap_ sur un des animaux, une nouvelle page comportant toutes les informations est affichée.
+
+## Création du projet
+
+```json
+.
+├── BindableLayoutSample
+│   ├── App.xaml
+│   ├── App.xaml.cs
+│   ├── AssemblyInfo.cs
+│   ├── BindableLayoutSample.csproj
+│   ├── DAO
+│   │   └── AnimalDAO.cs
+│   ├── Model
+│   │   └── Animal.cs
+│   ├── View
+│   │   ├── AnimalDetailsView.xaml
+│   │   │   └── AnimalDetailsView.xaml.cs
+│   │   └── AnimalListView.xaml
+│   │       └── AnimalListView.xaml.cs
+│   └── ViewModel
+│       ├── AnimalDetailsViewModel.cs
+│       ├── AnimalItemViewModel.cs
+│       ├── AnimalListViewModel.cs
+│       └── Base
+│           └── ViewModelBase.cs
+└── BindableLayoutSample.Android
+    └── ...
+```
+
+La première étape est de créer une application vide Xamarin.Forms.
+
+- Supprimer les fichiers `Main.xaml` et `Main.xaml.cs`, c'est une page créée par défaut dont on ne se servira pas
+- Créer les répertoires DAO, Model, View, ViewModel et le sous-répertoire Base dans ViewModel
+- Implémenter le modèle `Animal` (présenté plus haut)
+
+- Créer l’objet `AnimalDAO` (`AnimalDAO.cs`).
+
+```csharp
+// La classe d'accès aux données sur les animaux
+public class AnimalDAO
+{
+    public async Task<List<Animal>> GetAllAnimals()
+    {
+        // Génération de "fausses" données
+        List<Animal> ret = new List<Animal>()
+        {
+            new Animal()
+            {
+                AnimalID = 27852,
+                DateTraitement = DateTime.Parse("2022-08-05 14:26"),
+                Elevage = "PEIMA"
+            },
+            new Animal()
+            {
+                AnimalID = 2421,
+                DateTraitement = DateTime.Parse("2022-08-05 12:33"),
+                Elevage = "PEIMA"
+            },
+            new Animal()
+            {
+                AnimalID = 13569,
+                DateTraitement = DateTime.Parse("2022-08-06 08:14"),
+                Elevage = "Lees-Athas"
+            },
+            new Animal()
+            {
+                AnimalID = 45555,
+                DateTraitement = DateTime.Parse("2022-08-07 16:21"),
+                Elevage = "Donzacq"
+            },
+            new Animal()
+            {
+                AnimalID = 8956,
+                DateTraitement = DateTime.Parse("2022-08-07 18:01"),
+                Elevage = "PEIMA"
+            },
+        };
+
+        // Simulation d'attente d'accès aux données (WS, BDD, ...)
+        await Task.Delay(1000);
+        return ret;
+    }
+}
+```
+
+- Créer les _Views_ et _ViewModels_ en ajoutant public avant chaque déclaration mais en les laissant vides (pour l’instant…)
+- Faire le binding pour chaque paire _View - ViewModel_:
+
+Dans `AnimalDetailsView.xaml.cs`:
+
+```csharp
+public AnimalDetailsView()
+{
+    InitializeComponent();
+    BindingContext = new AnimalDetailsViewModel();
+}
+```
+
+Dans `AnimalListView.xaml.cs`:
+
+```csharp
+public AnimalListView()
+{
+    InitializeComponent();
+    BindingContext = new AnimalListViewModel();
+}
+```
+
+A noter que nous avons un 3ème _ViewModel_, `AnimalViewModel` qui n’a pas de _View_ liée :  c’est normal, on s’en occupera plus tard.
+
+- Implémenter le `ViewModelBase` qui implémente `INPC` (on utilisera la fonction `SetProperty` lors d'assignation de valeur sur nos propriétés)
+
+```csharp
+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));
+    }
+}
+```
+
+- Et finalement : définir la propriété `MainPage` dans `App.xaml.cs` sur `AnimalListView`. En le mettant dans une `NavigationPage`, on active la navigation hiercharchique (possibilité de revenir en arrière quand on navigue vers une nouvelle page).
+
+```csharp
+public App()
+{
+    InitializeComponent();
+
+    // Point d'entrée de l'application
+    MainPage = new NavigationPage(new AnimalListView());
+}
+```
+
+## La page d’accueil et chargement des données
+
+### Création de la liste
+
+Dans le fichier `AnimalListView.xaml`, nous allons itérer sur une liste d’animaux que l'on nommera `AnimalList`. Cette liste contient les données que l’on souhaite afficher. On devra donc définir comment ces informations doivent être affichées. De plus, sur chaque _tap_ on veut naviguer vers une page de détail de l’animal concerné. 
+
+Tout d'abord, on souhaite itérer sur `AnimalList` dans le fichier XAML. Chaque objet de liste comportera des éléments auxquels on pourra se lier à l’aide d’un _Binding_. En utilisant un _Binding_, on doit utiliser un nouveau _ViewModel_ pour chaque objet de la liste (les Views ne peuvent être bindées qu’à des _ViewModels_, c’est la règle MVVM!).
+
+On aura donc plusieurs _ViewModel_ liés à la même page… et c’est valide ! La règle étant qu’un _ViewModel_ **ne doit être lié qu’à une seule page**, rien ne nous empêche d’avoir plusieurs _ViewModel_ par page, et c’est même la manière de faire pour notre problématique.
+
+Pour pouvoir utiliser le _Binding_ et ajouter la fonctionnalité de navigation sans toucher au modèle animal, nous allons créer un nouveau _ViewModel_ : `AnimalItemViewModel`. Ce _ViewModel_ comportera les informations de l’animal ainsi que la commande de navigation vers la page de détail de cet animal.
+
+Le code de `AnimalItemViewModel.cs` donne :
+
+```csharp
+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());
+    }
+
+}
+```
+
+On instancie ensuite une liste observable (`ObservableCollection`) de ce modèle. Cette liste est ensuite alimentée avec les données de chaque animal chargé.
+
+Dans `AnimalListViewModel.cs`, déclaration de l'`ObservableCollection`:
+
+```csharp
+// 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 sur la fonction Add
+public ObservableCollection<AnimalItemViewModel> AnimalList { get; set; }
+```
+
+Alimentation de la liste (à mettre dans le constructeur ou dans une commande):
+
+```csharp
+// On alimente la liste observée par la view (AnimalList)
+foreach (Animal _animal in result)
+{
+    AnimalItemViewModel toAddItem = new AnimalItemViewModel(_animal);
+    AnimalList.Add(toAddItem);
+}
+```
+
+#### Et comment ça se passe du côté de l’affichage (le XAML) ?
+
+On veut créer une liste dans le XAML liée à notre `AnimalList` et en même temps gérer l’affichage en itérant chaque élément de la liste. Pour cela on utilise la propriété `BindableLayout` de la balise `StackLayout`.
+
+En liant la propriété `BindableLayout.ItemSource` à une liste observable (d’où `ObservableCollection`), on peut itérer sur notre liste dans le XAML et gérer l’affichage pour chaque itération. 
+
+Grâce à l'enchaînement de balises suivantes on peut personnaliser l’affichage de chaque élément:
+
+```xml
+<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>
+```
+
+Dans la balise `DataTemplate`, le _BindingContext_ change, au lieu d’être lié à la page `AnimalListView`, **il s’attache à l’élément traité par l’itération sur** `BindableLayout.ItemSource` donc à chaque `AnimalItemViewModel`. Ce fonctionnement est représenté sur le diagramme ci-dessous :
+
+Le reste de l'application pour obtenir les pages des captures d'écran ci-dessus est du développement Xamarin fondamental, décrit dans d'autres tutoriels et formations de ce wiki.
+L'ensemble du code source est disponible sur ce dépôt Git : https://forge-dga.jouy.inra.fr/projects/xamarin/repository/tuto_bindablelayout
+L'adresse du .git est : https://forge-dga.jouy.inra.fr/git/xamarin.tuto_bl.git
\ No newline at end of file
