Révision 61fbfe25

Voir les différences:

BindableLayoutSample/BindableLayoutSample.Android/MainActivity.cs
1
using System;
2

  
1

3 2
using Android.App;
4 3
using Android.Content.PM;
5 4
using Android.Runtime;
BindableLayoutSample/BindableLayoutSample.Android/Properties/AssemblyInfo.cs
1 1
using System.Reflection;
2
using System.Runtime.CompilerServices;
3 2
using System.Runtime.InteropServices;
4 3
using Android.App;
5 4

  
BindableLayoutSample/BindableLayoutSample/App.xaml.cs
1 1
using BindableLayoutSample.View;
2
using System;
3 2
using Xamarin.Forms;
4
using Xamarin.Forms.Xaml;
5 3

  
6 4
namespace BindableLayoutSample
7 5
{
......
11 9
        {
12 10
            InitializeComponent();
13 11

  
14
            MainPage = new AnimalListView();
12
            // Point d'entrée de l'application
13
            MainPage = new NavigationPage(new AnimalListView());
15 14
        }
16 15

  
17 16
        protected override void OnStart()
BindableLayoutSample/BindableLayoutSample/DAO/AnimalDAO.cs
1 1
using BindableLayoutSample.Model;
2 2
using System;
3 3
using System.Collections.Generic;
4
using System.Text;
5 4
using System.Threading.Tasks;
6 5

  
7 6
namespace BindableLayoutSample.DAO
8 7
{
8
    // La classe d'accès aux données sur les animaux
9 9
    public class AnimalDAO
10 10
    {
11 11
        public async Task<List<Animal>> GetAllAnimals()
12 12
        {
13
            // Génération de fausse données
13 14
            List<Animal> ret = new List<Animal>()
14 15
            {
15 16
                new Animal()
......
45 46
            };
46 47

  
47 48
            // Simulation d'attente d'accès aux données (WS, BDD, ...)
48
            await Task.Delay(500);
49
            await Task.Delay(1000);
49 50
            return ret;
50 51
        }
51 52
    }
BindableLayoutSample/BindableLayoutSample/MainPage.xaml.cs
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Linq;
5
using System.Text;
6
using System.Threading.Tasks;
7
using Xamarin.Forms;
1
using Xamarin.Forms;
8 2

  
9 3
namespace BindableLayoutSample
10 4
{
BindableLayoutSample/BindableLayoutSample/Model/Animal.cs
1 1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4 2

  
5 3
namespace BindableLayoutSample.Model
6 4
{
5
    // Le modèle Animal avec ses 3 propriétés et accesseurs
7 6
    public class Animal
8 7
    {
9 8
        public int AnimalID { get; set; }
BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml
4 4
    xmlns="http://xamarin.com/schemas/2014/forms"
5 5
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
6 6
    <ContentPage.Content>
7
        <StackLayout>
7
        <StackLayout Spacing="30" VerticalOptions="CenterAndExpand">
8
            <!--  Les infos de l'animal  -->
8 9
            <Label
10
                FontAttributes="Bold"
11
                FontSize="25"
9 12
                HorizontalOptions="CenterAndExpand"
10
                Text="!"
11
                VerticalOptions="CenterAndExpand" />
13
                Text="{Binding Animal.AnimalID, StringFormat='Animal n° {0}'}"
14
                TextColor="DarkCyan" />
15
            <Label
16
                FontAttributes="Italic"
17
                FontSize="20"
18
                HorizontalOptions="CenterAndExpand"
19
                Text="{Binding Animal.Elevage, StringFormat='Elevage: {0}'}"
20
                TextColor="DarkGray" />
21
            <!--
22
                L'enchainement &#..; permet d'avoir une chaine de code éxecutable
23
                dans une chaine de caractère, ici cela permet de créer un retour à la ligne
24
            -->
25
            <Label
26
                FontSize="18"
27
                HorizontalOptions="CenterAndExpand"
28
                HorizontalTextAlignment="Center"
29
                Text="{Binding Animal.DateTraitement, StringFormat='Date du dernier traitement:&#10; {0:ddd dd MMMM yyyy}'}"
30
                TextColor="Black" />
12 31
        </StackLayout>
13 32
    </ContentPage.Content>
14 33
</ContentPage>
BindableLayoutSample/BindableLayoutSample/View/AnimalDetailsView.xaml.cs
1
using BindableLayoutSample.ViewModel;
2
using System;
3
using System.Collections.Generic;
4
using System.Linq;
5
using System.Text;
6
using System.Threading.Tasks;
1
using BindableLayoutSample.Model;
2
using BindableLayoutSample.ViewModel;
7 3

  
8 4
using Xamarin.Forms;
9 5
using Xamarin.Forms.Xaml;
......
13 9
    [XamlCompilation(XamlCompilationOptions.Compile)]
14 10
    public partial class AnimalDetailsView : ContentPage
15 11
    {
16
        public AnimalDetailsView()
12
        public AnimalDetailsView(Animal animal)
17 13
        {
18 14
            InitializeComponent();
19
            BindingContext = new AnimalDetailsViewModel();
15
            BindingContext = new AnimalDetailsViewModel(animal);
20 16
        }
21 17
    }
22 18
}
BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml
3 3
    x:Class="BindableLayoutSample.View.AnimalListView"
4 4
    xmlns="http://xamarin.com/schemas/2014/forms"
5 5
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
6
    xmlns:xe="clr-namespace:XamEffects;assembly=XamEffects">
6
    xmlns:xe="clr-namespace:XamEffects;assembly=XamEffects"
7
    Title="BindableLayout Sample App">
7 8
    <ContentPage.Content>
8
        <StackLayout>
9
            <Label
9
        <Grid>
10
            <StackLayout
11
                Padding="60,10"
10 12
                HorizontalOptions="CenterAndExpand"
11
                Text="Animal List"
12
                VerticalOptions="CenterAndExpand" />
13
            <xe:BorderView xe:TouchEffect.Color="LightBlue" BackgroundColor="#4b6da6">
14
                <Label FontAttributes="Bold" Text="Load animals" />
15
            </xe:BorderView>
16
        </StackLayout>
13
                VerticalOptions="CenterAndExpand">
14
                <StackLayout>
15
                    <Label
16
                        FontSize="Medium"
17
                        HorizontalTextAlignment="Center"
18
                        Text="Animal list" />
19
                    <!--  Une border view de XamEffects est plus sympa qu'un bouton par défault  -->
20
                    <xe:BorderView
21
                        xe:Commands.Tap="{Binding LoadAnimalsCommand}"
22
                        xe:TouchEffect.Color="LightBlue"
23
                        BackgroundColor="#4b6da6"
24
                        CornerRadius="20"
25
                        HorizontalOptions="Center">
26
                        <Label
27
                            Margin="15,10"
28
                            FontAttributes="Bold"
29
                            Text="Load animals"
30
                            TextColor="White" />
31
                    </xe:BorderView>
32
                </StackLayout>
33

  
34
                <!--  La Frame est visible seulement si les animaux ont été chargés  -->
35
                <Frame
36
                    Padding="0,10,0,0"
37
                    BackgroundColor="Transparent"
38
                    BorderColor="#4b6da6"
39
                    CornerRadius="20"
40
                    HasShadow="False"
41
                    IsVisible="{Binding IsLoadedAnimals}">
42
                    <StackLayout Spacing="0">
43
                        <Grid ColumnDefinitions="*,2*">
44
                            <Label
45
                                Grid.Row="0"
46
                                Grid.Column="0"
47
                                FontAttributes="Bold"
48
                                HorizontalOptions="CenterAndExpand"
49
                                Text="ID"
50
                                TextColor="DarkCyan"
51
                                VerticalOptions="CenterAndExpand" />
52
                            <Label
53
                                Grid.Row="0"
54
                                Grid.Column="1"
55
                                FontSize="Medium"
56
                                HorizontalOptions="CenterAndExpand"
57
                                Text="Elevage"
58
                                TextColor="DarkGray" />
59
                        </Grid>
60
                        <BoxView
61
                            Margin="0,10,0,0"
62
                            HeightRequest="1"
63
                            HorizontalOptions="FillAndExpand"
64
                            Color="#4b6da6" />
65
                        <!--
66
                            On utilise une scroll view au cas ou beaucoup d'animaux sont chargés
67
                            On assure qu'ils soient tous accessible si la taille de la liste venait
68
                            à dépasser la taille de l'écran
69
                        -->
70
                        <ScrollView>
71
                            <StackLayout Padding="0,5" BindableLayout.ItemsSource="{Binding AnimalList}">
72
                                <!--
73
                                    On entre dans une itération sur BindableLayout.ItemSource donc AnimalList
74
                                -->
75
                                <BindableLayout.ItemTemplate>
76
                                    <!--
77
                                        Dans le dataTemplate, le BindingContext est lié à l'AnimalItemViewModel
78
                                        de l'itération
79
                                    -->
80
                                    <DataTemplate>
81
                                        <!--
82
                                            Lors du "tap", on utilise la commande de navigation définie
83
                                            dans AnimalItemViewModel
84
                                        -->
85
                                        <Grid
86
                                            Padding="5"
87
                                            xe:Commands.Tap="{Binding NavigateToAnimalCommand}"
88
                                            xe:TouchEffect.Color="#4b6da6"
89
                                            ColumnDefinitions="*,2*"
90
                                            RowDefinitions="Auto, Auto"
91
                                            RowSpacing="0">
92
                                            <!--
93
                                                Les infos qu'on cherche se trouve dans l'objet Animal de
94
                                                AnimalItemViewModel
95
                                            -->
96
                                            <Label
97
                                                Grid.Row="0"
98
                                                Grid.Column="0"
99
                                                FontAttributes="Bold"
100
                                                HorizontalOptions="CenterAndExpand"
101
                                                Text="{Binding Animal.AnimalID}"
102
                                                TextColor="DarkCyan"
103
                                                VerticalOptions="CenterAndExpand" />
104
                                            <Label
105
                                                Grid.Row="0"
106
                                                Grid.Column="1"
107
                                                FontSize="Medium"
108
                                                HorizontalOptions="CenterAndExpand"
109
                                                Text="{Binding Animal.Elevage}"
110
                                                TextColor="DarkGray" />
111
                                        </Grid>
112
                                    </DataTemplate>
113
                                </BindableLayout.ItemTemplate>
114
                            </StackLayout>
115
                        </ScrollView>
116
                    </StackLayout>
117
                </Frame>
118
            </StackLayout>
119
            <!--  Indicateur de travail en cours  -->
120
            <Grid Grid.RowSpan="1" IsVisible="{Binding IsBusy}">
121
                <BoxView BackgroundColor="White" Opacity="0.4" />
122
                <ActivityIndicator
123
                    HorizontalOptions="Center"
124
                    IsRunning="True"
125
                    Color="Green" />
126
            </Grid>
127
        </Grid>
17 128
    </ContentPage.Content>
18 129
</ContentPage>
BindableLayoutSample/BindableLayoutSample/View/AnimalListView.xaml.cs
1 1
using BindableLayoutSample.ViewModel;
2
using System;
3
using System.Collections.Generic;
4
using System.Linq;
5
using System.Text;
6
using System.Threading.Tasks;
7

  
8 2
using Xamarin.Forms;
9 3
using Xamarin.Forms.Xaml;
10 4

  
BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalDetailsViewModel.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
1
using BindableLayoutSample.Model;
2
using BindableLayoutSample.ViewModel.Base;
4 3

  
5 4
namespace BindableLayoutSample.ViewModel
6 5
{
7
    public class AnimalDetailsViewModel
6
    // Le ViewModel de la page d'information sur chaque animal
7
    // Instancié avec un objet de type Animal passé en argument
8
    public class AnimalDetailsViewModel : ViewModelBase
8 9
    {
10
        private Animal animal;
11

  
12
        public Animal Animal
13
        {
14
            get => animal;
15
            set => SetProperty(ref animal, value);
16
        }
17

  
18
        public AnimalDetailsViewModel(Animal _animal)
19
        {
20
            Animal = _animal;
21
        }
9 22
    }
10 23
}
BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalItemViewModel.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
1
using BindableLayoutSample.Model;
2
using BindableLayoutSample.View;
3
using BindableLayoutSample.ViewModel.Base;
4
using System.Threading.Tasks;
5
using System.Windows.Input;
6
using Xamarin.Forms;
4 7

  
5 8
namespace BindableLayoutSample.ViewModel
6 9
{
7
    public class AnimalItemViewModel
10
    public class AnimalItemViewModel : ViewModelBase
8 11
    {
12
        private Animal animal;
13

  
14
        // Les infos de l'animal
15
        public Animal Animal
16
        {
17
            get => animal;
18
            set => SetProperty(ref animal, value);
19
        }
20

  
21
        // La commande de navigation est asynchrone,
22
        // Pour ne pas bloquer le Thread principal en charge de l'affichage
23
        // pendant l'instanciation de la nouvelle Page
24
        private async Task NavigateToAnimalDetails()
25
        {
26
            // Petite attente pour rendre la transition plus fluide
27
            await Task.Delay(150);
28

  
29
            // L'utilisation de la navigation page nous permet d'avoir une navigation verticale (push & pop)
30
            await Application.Current.MainPage.Navigation.PushAsync(new AnimalDetailsView(Animal));
31
        }
32

  
33
        public ICommand NavigateToAnimalCommand { private set; get; }
34

  
35
        public AnimalItemViewModel(Animal _animal)
36
        {
37
            Animal = _animal;
38
            NavigateToAnimalCommand = new Command(async () => await NavigateToAnimalDetails());
39
        }
40

  
9 41
    }
10 42
}
BindableLayoutSample/BindableLayoutSample/ViewModel/AnimalListViewModel.cs
1
using System;
1
using BindableLayoutSample.DAO;
2
using BindableLayoutSample.Model;
3
using BindableLayoutSample.ViewModel.Base;
2 4
using System.Collections.Generic;
3
using System.Text;
5
using System.Collections.ObjectModel;
6
using System.Threading.Tasks;
7
using System.Windows.Input;
8
using Xamarin.Forms;
4 9

  
5 10
namespace BindableLayoutSample.ViewModel
6 11
{
7
    public class AnimalListViewModel
12
    // Le ViewModel de la page d'affichage de la liste d'animaux
13
    public class AnimalListViewModel : ViewModelBase
8 14
    {
15
        #region Attributes
16

  
17
        private bool isBusy;
18
        private bool isLoadedAnimals;
19

  
20
        #endregion
21

  
22
        #region Properties
23
        // Indicateur de travail en cours
24
        public bool IsBusy
25
        {
26
            get => isBusy;
27
            set => SetProperty(ref isBusy, value);
28
        }
29

  
30
        // Indicateur sur l'état de chargement des données animaux
31
        public bool IsLoadedAnimals
32
        {
33
            get => isLoadedAnimals;
34
            set => SetProperty(ref isLoadedAnimals, value);
35
        }
36

  
37
        // La liste d'animaux qui sera alimentée avec les données récupérées par la DAO
38
        // L'objet ObservableCollection implémente directement INPC
39
        public ObservableCollection<AnimalItemViewModel> AnimalList { get; set; }
40

  
41
        #endregion
42

  
43
        #region Commands
44
        // La commande de chargement des données animaux
45
        // Asynchrone pour ne pas bloquer le thread principal
46
        // et donc pour ne pas bloquer l'affichage
47
        private async Task LoadAnimalCommand()
48
        {
49
            IsBusy = true;
50
            IsLoadedAnimals = false;
51
            AnimalList.Clear();
52

  
53
            AnimalDAO dao = new AnimalDAO();
54
            List<Animal> result = await dao.GetAllAnimals();
55
            
56
            // On alimente la liste observée par la view (AnimalList)
57
            foreach (Animal _animal in result)
58
            {
59
                AnimalItemViewModel toAddItem = new AnimalItemViewModel(_animal);
60
                AnimalList.Add(toAddItem);
61
            }
62

  
63
            IsLoadedAnimals = true;
64
            IsBusy = false;
65
        }
66

  
67
        public ICommand LoadAnimalsCommand { private set; get; }
68
        #endregion 
69
        
70
        // CTOR
71
        public AnimalListViewModel()
72
        {
73
            // Il important d'initialiser les listes d'un ViewModel pour éviter
74
            // les NullPointerExceptions
75
            AnimalList = new ObservableCollection<AnimalItemViewModel>();
76
            LoadAnimalsCommand = new Command(async () => await LoadAnimalCommand());
77
        }
9 78
    }
10 79
}
BindableLayoutSample/BindableLayoutSample/ViewModel/Base/ViewModelBase.cs
1
using System.ComponentModel;
2
using System.Runtime.CompilerServices;
3

  
4
namespace BindableLayoutSample.ViewModel.Base
5
{
6
    public class ViewModelBase : INotifyPropertyChanged
7
    {
8
        // Propriété de notification de changement
9
        public event PropertyChangedEventHandler PropertyChanged;
10

  
11
        // Procédure de changement de valeur
12
        // Déclenche la fonction de notification
13
        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyname = null)
14
        {
15
            if (Equals(storage, value))
16
            {
17
                return false;
18
            }
19

  
20
            storage = value;
21
            OnPropertyChanged(propertyname);
22
            return true;
23
        }
24

  
25
        // Fonction de notification 
26
        // Déclenche l'évènement de changement de valeur
27
        // Avec en argument le nom de la propriété qui a changé
28
        protected void OnPropertyChanged(string propertyName)
29
        {
30
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
31
        }
32

  
33
        public ViewModelBase()
34
        {
35

  
36
        }
37

  
38
    }
39
}

Formats disponibles : Unified diff