Révision 61fbfe25
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: {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