0% ont trouvé ce document utile (0 vote)
14 vues100 pages

X Amar Informs

Le document présente un aperçu du développement d'applications mobiles avec Xamarin.Forms et C#. Il aborde les différences entre les plateformes iOS, Android et Windows, ainsi que les environnements de développement et les langages de programmation associés. Il décrit également la structure d'une application Xamarin, l'utilisation de XAML pour la conception d'interfaces, et les méthodes de navigation entre les pages.

Transféré par

richezatr
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PPTX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
14 vues100 pages

X Amar Informs

Le document présente un aperçu du développement d'applications mobiles avec Xamarin.Forms et C#. Il aborde les différences entre les plateformes iOS, Android et Windows, ainsi que les environnements de développement et les langages de programmation associés. Il décrit également la structure d'une application Xamarin, l'utilisation de XAML pour la conception d'interfaces, et les méthodes de navigation entre les pages.

Transféré par

richezatr
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PPTX, PDF, TXT ou lisez en ligne sur Scribd

XAMARIN FORMS C#

Wilfart Emmanuel
3ième informatique
Le marché des mobiles
• Nous retrouvons sur le marché des mobiles
deux grands acteurs:
– Appel avec ses IPhone et IPad et son système
d'exploitation iOS
– Google et son système d'exploitation Android
utilisé par de nombreux fabricants de
smartphones et tablettes
Le marché des mobiles
• Chacune de ces plateformes apportent leurs
caractéristiques propres:
– Façon différente de naviguer entre les
applications et les pages.
– Convention différente de représenter les
données.
– Façon différente d'appeler et d'afficher les
menus.
– Gestion différente du touché
Le marché des mobiles
• Les environnements de développement:
– Pour le développement iOS, Xcode sur Mac.
– Pour le développement Android, Android Studio
sur diverses plates-formes.
– Pour le développement Windows, Visual Studio
sur PC
Le marché des mobiles
• Les interfaces de programmation différentes.
Bien que similaires, les objets d'interface
utilisateur ont des noms différents. Exemple
pour un toggle ( basculement de valeur
booléenne)
– Pour IPhone et IPad: View appelée UISwitch
– Pour Android: Widget appelé Switch
– Pour Windows: Control appelé ToggleSwitch
Le marché des mobiles
• Des langages de programmation différents
– Pour IPhone et IPad: Obective-C
– Pour Android: Java
– Pour Windows: C#

Une solution serait d'envisager trois équipes de développeurs spécialisés pour


chaque plateforme ce qui augmente le cout de développement d'une même
application portable dans les différents environnements
Le C# et la technologie .NET
• Microsoft donne naissance à sa
technologie .NET en 2000.
• Au premier .NET Framework 1.0 est associé le
langage C# dans sa version 1.0.
• La version Visual Studio .NET 2002 intègre le
C#.
Le Framework .NET n'existe que dans les environnements Microsoft. Les autres
systèmes d'exploitation en sont dépourvus.
C'est donc à l'époque un environnement propre à Microsoft
Bien que.... le langage C# est normalisé
Les projets de portabilité
• En 2000, la société Ximian (Miguel de Icaza et
Nat Friedman) lance un projet open source
appelé Mono afin de créer une
implémentation du compilateur C # et du .NET
Framework sous Linux.
• En 2003, la société Ximian est rachetée par
Novell.
• En 2011 rachat de Novell par Attachmate et
création de la société Xamarin. Mono forme la
base d'une solution mobile Cross-Plateform
Les projets de portabilité
• En 2016, Microsoft rachète Xamarin et
[Link] est maintenant gratuitement
disponible avec Visual Studio.
• Xamarin comprend trois librairies:
– [Link] (Provenant du projet MonoMac)
– [Link] (Provenant du projet MonoTouch)
– [Link] (Provenant du projet
MonoDroid)
Les projets de portabilité
• Visual studio permet sans restriction aucune,
de pouvoir développer des applications sous
Android
• Pour le développement sous iOS, vous devez:
– Posséder un Mac avec iOS.
– Installer Xcode.
– Effectuer une opération de pairage entre Visual
Studio sous Windows et votre Mac.
– Même l'émulation IPhone ne sera possible que
dans ces conditions.
Cross-platform et MVVM
• Les différences entre plateformes résident
principalement dans l'aspect graphique
• Le traitement des données reste en général
indépendant de la plateforme.
• L'utilisation du modèle MVVM (Model-View-
ViewModel) est donc conseillée dans ce type de
développement.
• Le code indépendant peut être placé dans un
projet séparé soit Shared Asset Project (SAP) ou
Portable Class Library (PCL) sous forme d'une
DLL
Cross-platform et MVVM
Xamarin C# Compiler
• Pour iOS, le compilateur Xamarin génère un
code dans un langage intermédiaire qui est
ensuite compilé par le compilateur Apple
• Pour Android, Xamarin compile dans un
langage intermédiaire qui sera exécuté par la
version Mono installée sur le périphérique
[Link]
[Link]
[Link]
Première application
Première application
Première application

Nous retrouvons bien dans notre solution 3 projets.


Un projet commun et un projet pour chaque plate-forme sélectionnée
[Link] et XAML

[Link] prend en charge le langage XAML (prononcé "Zammel")


C'est un langage basé XML permettant de définir dans un fichier séparé la structure
graphique de notre interface utilisateur
[Link] et XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="[Link]

xmlns:x="[Link]
xmlns:local="clr-namespace:App14"
x:Class="[Link]">

<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to [Link]!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>

</ContentPage>

Nous ajouterons quelques éléments évoqués ultérieurement tels que le Switch.


[Link] et XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="[Link]

xmlns:x="[Link]
xmlns:local="clr-namespace:App14"
x:Class="[Link]">

<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to [Link]!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>

</ContentPage>

Nous ajouterons quelques éléments évoqués ultérieurement tels que le Switch.


[Link] et XAML
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to [Link]!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text = "Click Me!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Switch VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Slider VerticalOptions="CenterAndExpand" />
</StackLayout>
[Link] et Android
L'exécution sous Android peut se réaliser de multiples façons: sous un émulateur ou
sur tout smartphone connecté sur un port USB.

Dans notre exemple, nous retrouvons par défaut l'émulateur mais aussi le Samsung
SM-J530F qui peut être sélectionné.
[Link] et Android
Sous l'émulateur, nous obtiendrons alors le résultat suivant
[Link] et iOS
Comme renseigné au préalable, l'utilisation de l'émulateur iOS réclame que vous ayez
un MAC avec Xcode d'installé.
Lors du pairage, la mise à jour de Mono et [Link] se feront. Veillez à ce que la
version de Xcode permette l'utilisation de la version de l'iOS configuré. Une mise à
jour sera peut-être nécessaire
[Link] et iOS
[Link] et iOS
Tester une application sur un IPhone physique est moins simple que pour Android.
Le Free Provisioning permet aux développeurs [Link] de déployer et de tester
leurs applications sur des appareils iOS sans faire partie du programme pour
développeurs Apple.

Le certificat de test créé n'a qu'une validité de 6 jours ce qui limite vos possibilités

[Link]
ning/free-provisioning?tabs=windows
[Link] et iOS
Dans une première démarche, il faudra renseigner votre de compte de développeur
personnel dans les paramètres de configuration de Visual Studio
[Link] et iOS
[Link] et iOS
Il faudra être attentif à l'identifiant du bundle entre le projet dans Visual Studio et
l'environnement de configuration XCode

Dans notre exemple, l'identifiant du bundle est [Link]


[Link] et iOS
Sous Xcode, nous aurons les étapes suivantes à réaliser. Vous devez créer un nouveau
projet avec les caractéristiques suivantes:
[Link] et iOS
[Link] et iOS
Il nous reste à finaliser le paramétrage de la signature iOS du bundle au niveau de
Visual Studio
[Link] anatomie
Dans [Link], les objets qui apparaissent à l'écran sont collectivement
appelés "visual elements". Nous retrouvons trois catégories:

• Page Dans notre application ContentPage est un type de page


• Layout Dans notre application, StackLayout est un type de layout
• View Dans notre application, tout objet graphique interactif est un type
View. Nous retrouvons par exemple: Label, Button, Switch, Slider...

Ayant configuré notre première application pour travailler avec une application crosse
plateforme pour iOS et Android, nous aurons la structure des projets suivants dans
notre solution.
[Link] anatomie
Un projet correspond à l'application elle même et au chargement de la page. Une
référence à ce projet est incluse dans les deux autres projets
[Link] anatomie
La solution inclut des packages NuGet associés à Xamarin et qu'il est possible de
mettre à jour.

Dans notre exemple, le projet App14 comprend la classe App qui sera responsable
du rendu de la page qui est affichée à l'exécution de l'application en initialisant la
référence MainPage de cette classe
[Link] anatomie
public partial class App :
Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
}

Notre application se base sur la couche présentation de notre application reposant


sur un fichier Xaml. En regardant le contenu de ce fichier, nous retrouvons une
association entre la ContentPage et la propriété MainPage

<ContentPage
xmlns="[Link]
xmlns:x="[Link]
xmlns:local="clr-namespace:App14"
x:Class="[Link]">
[Link] anatomie
public partial class MainPage : ContentPage

Remarquons la classe MainPage comme étant une classe partielle partageant ainsi la
même classe associée au fichier Xaml

Dans les deux autres projets, nous retrouvons la même structure de dossiers tels que:

• Les références: (liste des assemblages dont la projet a besoin). Nous retrouvons
notamment le projet lié à notre classe App
• Les Assets: ils permettent d'inclure des fichiers arbitraires tels que du texte, du
code XML, des polices, de la musique et des vidéos dans votre application. Si vous
essayez d'inclure ces fichiers en tant que "ressources", Android les traitera dans
son système de ressources et vous ne pourrez pas obtenir les données brutes.
• Les ressources: les ressources sont stockées dans un dictionnaire de ressources.
Elles peuvent comprendre des styles, des modèles de contrôle, des modèles de
données, des couleurs et les convertisseurs...
[Link] projet Android
La notion d'activité est importante sous Android. L'activité sert de point d'entrée pour
l'interaction d'une application avec l'utilisateur.
Nous retrouvons sous le projet [Link] une classe correspondante

Nous pouvons analyser les éléments importants figurant dans cette classe.
[Link] projet Android
[Activity(Label = "App14", Icon = "@mipmap/icon", Theme =
"@style/MainTheme", MainLauncher = true,
ConfigurationChanges = [Link] |
[Link])]
public class MainActivity :
global::[Link]
ity
{
protected override void OnCreate(Bundle
savedInstanceState)
{
TabLayoutResource = [Link];
ToolbarResource = [Link];
[Link](savedInstanceState);
global::[Link](this,
savedInstanceState);
LoadApplication(new App());
}
}
[Link] projet Android
Remarquons les éléments suivants:

• LoadApplication(new App()); La méthode LoadApplication reçoit en argument


l'instance de notre classe App dont nous avons parlé précédemment.
• Attribut Activity comprenant notamment les arguments suivants:

• Theme = "@style/MainTheme". Remarquons que ce thème se trouve défini


dans les ressources du projet.
• ConfigurationChanges. Permet de définir qu'une activité ne doit pas être
recréée dans certaines circonstances telles que par exemple une rotation
d'écran.
• void OnCreate(Bundle savedInstanceState). Pour comprendre les raisons d'exister
de l'argument savedInstanceState, il est important de comprendre le cycle de vie
d'une activité.
[Link] projet Android
[Link] projet Android
savedInstanceState est un dictionnaire permettant de stocker et de transmettre des
informations d’état et des objets entre activités Si savedInstanceState n’est pas null,
cela indique que l’activité est en train de redémarrer et que son état doit être
restauré à partir de l’instance précédente.
[Link] projet iOS
Nous retrouvons la classe AppDelegate. Cette classe est responsable du lancement du
l'interface utilisateur de l'application en surchargeant la méthode FinishedLaunching.
Dans cette surcharge nous retrouvons

LoadApplication(new App());
[Link] Navigation

Nous retrouvons la classe NavigationPage permettant de gérer une pile de


pages de type LIFO dans laquelle nous pouvons nous balader d'une page à
l'autre. Chaque page possède une barre de navigation reprenant le titre de la
page ainsi qu'un bouton pour revenir à la page précédente.
[Link] NavigationPage
Une première démarche dans la classe App est d'ajouter une page racine (Root).
Il suffira d'utiliser la syntaxe suivante

public App()
{
InitializeComponent();
MainPage = new NavigationPage(new Page1());
}

L'application ressemble à l'utilisation d'une application avec une seule page déjà
utilisée précédemment. Nous allons maintenant envisager le code permettant
d'ajouter une nouvelle page dans la pile de page.
[Link] NavigationPage
[Link] NavigationPage
Nous modifions la page racine pour inclure un bouton permettant d'ajouter sur la
pile une seconde page. Nous ajouterons également des titres pour chacune des
pages.

Nous commencerons par ajouter une nouvelle page de contenu à notre projet
[Link] NavigationPage
Voici le code XAML permettant l'ajout du bouton dans la page racine

<[Link]>
<StackLayout>
<Label Text="Welcome to [Link]!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<Button Text="Go to page2"
Clicked="Button_Clicked"></Button>
</StackLayout>
</[Link]>

Voici le code C# associé au clic sur le bouton permettant l'ajout de la page sur la pile

private void Button_Clicked(object sender, EventArgs e)


{
[Link](new Page2());
}
[Link] NavigationPage

Remarquons le lien permettant le retour vers la page racine. Ce lien peut être
supprimé si vous souhaitez gérer ce retour vous même.
[Link] NavigationPage
Analysons rapidement la liste des méthodes utiles nous permettant de
personnaliser nos pages

[Link](); Permet de supprimer la page active de la pile et remonter


d'un niveau.
[Link](); Permet de supprimer de la pile toutes les pages à
l'exception de la page racine.
[Link](page, false); Permet de supprimer
l'affichage de la barre de navigation supérieure.

private void Button_Clicked(object sender, EventArgs e)


{
var page = new Page2();
[Link](page);
[Link](page, false);
}

[Link](page, false); Permet de supprimer le bouton de


retour de la barre de navigation
[Link] TabbedPage
Ce type de page comprendra deux parties:

• une TabbedBar comprenant la liste des pages sous forme, pour chacune d'elle,
d'une icône et d'un titre.
• Une ContentPage permettant l'affichage de la page sélectionnée.

Nous préférons démarrer notre application sur un modèle vide composé uniquement
d'une ContentPage que nous adapterons. Une fois l'application créée, nous devons
définir que notre page principale est une TabbedPage à la fois dans le code XAML mais
aussi dans le code C#

public partial class MainPage : TabbedPage


{
public MainPage()
{
InitializeComponent();
}
}
[Link] TabbedPage
<TabbedPage
xmlns="[Link]

xmlns:x="[Link]
xmlns:local="clr-namespace:App19"
x:Class="[Link]">
<[Link]>
<ContentPage Title="Restore" Icon="[Link]">
<[Link]>
<StackLayout VerticalOptions="Center"
HorizontalOptions="Center">
<Label Text="Restore page "></Label>
</StackLayout>
</[Link]>
</ContentPage>
<[Link]>
</TabbedPage>
Les content pages peuvent être remplacées par des pages de navigation si
nécessaire. Remarquons les attributs Title et Icon permettant de compléter la
TabbedBar.
[Link] TabbedPage
[Link] TabbedPage
Les contentpages peuvent être placés dans des fichiers séparés. Nous ajoutons une
nouvelle page "A propos de" qui sera dans un fichier XAML séparé.

<ContentPage
xmlns="[Link]
xmlns:x="[Link]
x:Class="[Link]" Title="About" Icon="[Link]">
<[Link]>
<StackLayout VerticalOptions="Center"
HorizontalOptions="Center">
<Label Text="About page"></Label>
</StackLayout>
</[Link]>
</ContentPage>
Dans la TabbedPage, il suffira d'ajoutez à la suite des pages existantes le code
suivant...

<local:About></local:About>
[Link] CarouselPage
Ce type de page permet de naviguer d'une contentpage (pas de navigationPage) à
l'autre par effet de glissement latéral. Dans sa structure de mise en place, elle
ressemble très fortement à la technologie vue précédemment.

Nous préférons démarrer notre application sur un modèle vide composé


uniquement d'une ContentPage que nous adapterons. Une fois l'application créée,
nous devons définir que notre page principale est une CarouselPage à la fois dans le
code XAML mais aussi dans le code C#

public partial class MainPage : CarouselPage


{
public MainPage()
{
InitializeComponent();
}
}
[Link] CarouselPage
<[Link]>
<ContentPage Title="Content Page 1">
<[Link]>
<StackLayout VerticalOptions="Center"
HorizontalOptions="Center">
<Label Text="Content Page 1"></Label>
</StackLayout>
</[Link]>
</ContentPage>
<ContentPage Title="Content Page 2">
<[Link]>
<StackLayout VerticalOptions="Center"
HorizontalOptions="Center">
<Label Text="Content Page 2"></Label>
</StackLayout>
</[Link]>
</ContentPage>
</[Link]>
[Link] CarouselPage
Les contentpages peuvent être placés dans des fichiers séparés.

<ContentPage
xmlns="[Link]
xmlns:x="[Link]
x:Class="[Link]">
<[Link]>
<StackLayout>
<Label Text="Welcome to [Link]!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</[Link]>
</ContentPage>
Dans la CarouselPage, il suffira d'ajoutez à la suite des pages existantes le code
suivant...

<local:MyContentPage></local:MyContentPage>
[Link] Ressources
Chaque ressource possède des attributs auxquels nous pouvons affecter des valeurs.
Nous reprenons le cas d'une application simple contenant une page de contenu
unique sous forme d'un formulaire.

<StackLayout HorizontalOptions="Center">
<Label Text="Formulaire d'inscription"></Label>
<Label Text="Nom"></Label>
<Entry></Entry>
<Label Text="Prenom"></Label>
<Entry></Entry>
<Button Text="Soumettre"></Button>
</StackLayout>

HorizontalOptions="Center" est une exemple d'attribut permettant le


centrage horizontal du contenu de notre StackLayout. Les attributs permettent
d'affiner la mise en page du formulaire
[Link] Ressources
<ContentPage
xmlns="[Link]
xmlns:x=
[Link]
xmlns:local="clr-namespace:App24"
x:Class="[Link]"
BackgroundColor="LightGray">
<StackLayout HorizontalOptions="Center"
BackgroundColor="LightGray">
<Label Margin="0,20,0,40" TextColor="Black"
FontSize="30" Text="Formulaire
d'inscription"></Label>
<Label FontSize="20" TextColor="Blue"
Text="Nom"></Label>
<Entry></Entry>
<Label FontSize="20" TextColor="Blue"
Text="Prenom"></Label>
<Entry></Entry>
<Button HeightRequest="60" Margin="0,40,0,0"
Text="Soumettre"></Button>
[Link] Ressources
BackgroundColor="LightGray"
HorizontalOptions="Center"
BackgroundColor="LightGray"
Margin="0,20,0,40"
TextColor="Black"
FontSize="30"
HeightRequest="60"

Ce sont des attributs de mise en page qui ont été ajoutés dans les balises
d'ouvertures des conteneurs appartenant à la page de contenu.

Tout comme les feuilles de style pour la mise en page HTML, une gestion simple des
attributs de mise en page consiste à les regrouper. Pour ce faire, nous pouvons, dans
un premier temps, définir les valeurs au moyen d'une librairie de ressources
[Link] Ressources
<[Link]>
<ResourceDictionary>
<Color x:Key="LabelColor">Black</Color>
</ResourceDictionary>
</[Link]>

Nous définissons notre propre ressource de couleur identifiée par la clef


x:Key="LabelColor". Nous pouvons alors utiliser cette ressource comme
valeur d'attribut.

<Label Margin="0,20,0,40" TextColor="{StaticResource


LabelColor}" FontSize="30" Text="Formulaire
d'inscription"></Label>

Nous pouvons définir de multiples valeurs les unes à la suite des autres de la façon
suivante
[Link] Ressources
<[Link]>
<ResourceDictionary>
<Color x:Key="TitleColor">Black</Color>
<x:Double x:Key="TitleSize">30</x:Double>
</ResourceDictionary>
</[Link]>

L'intérêt est de pouvoir très facilement modifier la valeur sans devoir parcourir
l'entièreté du fichier XAML.

Malgré tout, appliquer de multiples propriétés identiques pour, dans notre exemple,
les labels, demande de les ajouter pour chacun d'eux. Nous pouvons alors définir des
styles.
[Link] Styles
<[Link]>
<ResourceDictionary>
<Color x:Key="TitleColor">Black</Color>
<x:Double x:Key="TitleSize">20</x:Double>
</ResourceDictionary>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="15" />
</Style>
</[Link]>

Le conteneur Style contient des Setter dans lesquelles nous associerons la propriété
que nous souhaitons définir et la valeur correspondante. La clef n'est pas
indispensable si nous souhaitons que ce style soit global à tous les labels dans notre
exemple.
La cible graphique affectée par le style est définie dans l'attribut TargetType.

<Label Style="{StaticResource LabelStyle}"


Text="Nom"></Label>
[Link] Styles et héritage
Nous pouvons définir un style de base dont d'autres styles pourraient hériter.
Dans notre exemple, nous ajoutons un label qui aurait les mêmes propriétés que le
style défini précédemment mais avec des attributs supplémentaires de définis

<Style x:Key="LabelStyle" TargetType="Label">


<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="15" />
</Style>
<Style x:Key="LabelStyle2" BasedOn="{StaticResource
LabelStyle}" TargetType="Label">
<Setter Property="FontFamily"
Value="Underline"></Setter>
</Style>

BasedOn="{StaticResource LabelStyle}"nous permet de définir cet


héritage
[Link] Styles
Le style peut être défini pour une page comme nous venons de faire mais il peut être
également défini pour l'ensemble de l'application. Pour ce faire il suffira de définir les
ressources au niveau de l'application elle même.

<Application xmlns="[Link]
xmlns:x=
[Link]
x:Class="[Link]">
<[Link]>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="Blue" />
<Setter Property="FontSize" Value="15" />
</Style>
</[Link]>
</Application>
[Link] ControlTemplate
Dans le point précédent, nous avons vu qu'il était possible de définir un style.
Nous allons voir qu'il est possible également de définir un thème (apparence de la
page) pour l'application ou pour une page.

Le ControlTemplate se crée dans la partie consacrée aux ressources.


[Link] ControlTemplate
<ControlTemplate x:Key="MasterTheme">
<Grid>
<[Link]>
<RowDefinition Height="0.1*" />
<RowDefinition Height="0.8*" />
<RowDefinition Height="0.1*" />
</[Link]>
<BoxView CornerRadius="5" Color="LightGray" />
<Label Margin="10,0,0,0" Text="Inscription"
TextColor="Blue" VerticalOptions="Center" />
<ContentPresenter [Link]="1" />
<BoxView CornerRadius="5" [Link]="2"
Color="LightGray" />
<Label Margin="10,0,0,0" [Link]="2"
Text="Copyright 2019" TextColor="Blue"
VerticalOptions="Center" />
</Grid>
</ControlTemplate>
[Link] ControlTemplate
<ContentPresenter [Link]="1" /> permet de définir l'emplacement du
modèle ou doit être intégré le contenu de la page.

Au niveau de la page, il faudra définir le modèle avec lequel on travaille.

<ContentView Padding="5" ControlTemplate="{StaticResource


MasterTheme}">
<StackLayout VerticalOptions="FillAndExpand">
<Entry Text="Nom"></Entry>
<Entry Text="Prenom"></Entry>
<Entry Text="Mail"></Entry>
<Button Text="Soumettre"></Button>
</StackLayout>
</ContentView>

Il est possible de pouvoir commuter d'un modèle à un autre au niveau programmation


[Link] ControlTemplate
<StackLayout VerticalOptions="FillAndExpand">
<Entry Text="Nom"></Entry>
<Entry Text="Prenom"></Entry>
<Entry Text="Mail"></Entry>
<Button Text="Soumettre"></Button>
<Button Text="Changer le thème"
Clicked="Button_Clicked"></Button>
</StackLayout>

private void Button_Clicked(object sender, EventArgs e) {


var OrgTemp =
(ControlTemplate)[Link]["MasterTheme
"];
if ([Link]==OrgTemp)
[Link] =

(ControlTemplate)[Link]["MasterTheme
2"];
else
[Link] =
[Link] ControlTemplate
[Link] Custom Renderer
Il se peut que les ressources graphiques ne correspondent pas à vos attentes et que
vous souhaitiez les adapter à vos envies... C'est la que les Custom Renderer entrent
en action.

Imaginons que l'on souhaite des entrées avec des bords et que ceux ci soient
arrondis.
Nous aborderons dans un deuxième exemple des entrées mais comprenant une icône
personnalisable sur la gauche.

La première démarche est de créer une classe dans la partie commune permettant
son utilisation au niveau de la couche métier commune.

namespace App26
{
public class CustomEntryRenderer:Entry
{
}
}
[Link] Custom Renderer
Cette nouvelle classe peut être utilisée dans notre page de contenu sous la forme
suivante

<StackLayout VerticalOptions="FillAndExpand">
<Label Text="Nom"/>
<local:CustomEntryRenderer />
</StackLayout>

Si nous souhaitons adapter la façon dont cette entrée doit être représentée
graphiquement, nous devons passer par les API de chaque système d'exploitation
correspondants. Nous intégrerons la syntaxe commune pour ensuite adapter le code.
[Link] Custom Renderer
Pour IOS
Nous ajouterons une classe dans le projet lié à IOS

using [Link];
[assembly: ExportRenderer(typeof(CustomEntryRenderer),
typeof(CustomEntryRendererIOS))]
namespace [Link]
{
public class CustomEntryRendererIOS:EntryRenderer
{
protected override void
OnElementChanged(ElementChangedEventArgs<Entry> e)
{
[Link](e);
}
} }
[Link] Custom Renderer
Pour Androïd
Nous ajouterons une classe dans le projet lié à Androïd

using [Link];
[assembly: ExportRenderer(typeof(CustomEntryRenderer),
typeof(CustomEntryRendererAndroid))]
namespace [Link]
{
public class CustomEntryRendererAndroid:EntryRenderer
{
public CustomEntryRendererAndroid(Context context)
: base(context){}
protected override void
OnElementChanged(ElementChangedEventArgs<Entry> e)
{
[Link](e);
}
} }
[Link] Custom Renderer
Pour IOS
Pointons les éléments suivants importants:

using [Link];

[assembly: ExportRenderer(typeof(CustomEntryRenderer),
typeof(CustomEntryRendererIOS))]
L'attribut ExportRenderer enregistre le rendu avec [Link].

public class CustomEntryRendererIOS:EntryRenderer


La classe EntryRenderer expose la méthode OnElementChanged, appelée lorsque le
contrôle [Link] est créé pour restituer le contrôle natif correspondant

protected override void


OnElementChanged(ElementChangedEventArgs<Entry> e)
C'est dans cette méthode que nous placerons notre code adapté
[Link] Custom Renderer
Pour Android
Pointons les éléments suivants importants:

using [Link];

[assembly: ExportRenderer(typeof(CustomEntryRenderer),
typeof(CustomEntryRendererAndroid))]
L'attribut ExportRenderer enregistre le rendu avec [Link].

public class CustomEntryRendererAndroid:EntryRenderer


La classe EntryRenderer expose la méthode OnElementChanged, appelée lorsque le
contrôle [Link] est créé pour restituer le contrôle natif correspondant

protected override void


OnElementChanged(ElementChangedEventArgs<Entry> e)
C'est dans cette méthode que nous placerons notre code adapté
[Link] Custom Renderer
Maintenant nous pouvons placer dans la méthode
OnElementChanged(ElementChangedEventArgs<Entry> e)
le code adapté pour chaque API liée au système d'exploitation correspondant

Voici le code pour chaque environnement


[Link] Custom Renderer
Pour IOS
[Link](e);
if ([Link] != null || [Link] == null)
return;
if (Control!=null)
{
[Link] = 20;
[Link] = 3f;
[Link] = [Link]();
[Link] =
[Link]();
[Link] = new UIView(new CGRect(0, 0, 10,
0));
[Link] = [Link];
}
[Link] Custom Renderer
Pour Android
[Link](e);
if ([Link] != null || [Link] == null)
return;
if (Control!=null)
{
var GrdRawable = new GradientDrawable();
[Link](60f);
[Link](5, [Link]);
[Link]([Link]);
[Link](GrdRawable);
[Link](50, [Link],
[Link], [Link]);
}

Le code que l'on retrouve sous Android peut être remplacé par un fichier xml
définissant le Layout. Il suffira alors de charger le fichier.
[Link] Custom Renderer
Pour Android
<?xml version="1.0" encoding="utf-8" ?>

<shape
xmlns:android="[Link]
android:shape="rectangle"
android:padding="50dp">

<solid android:color="#fff"></solid>
<corners android:radius="60dp"></corners>
<stroke android:width="2dp"
android:color="#000"></stroke>

</shape>

if (Control!=null)
{ [Link]([Link]
[Link]); }
[Link] ListView
De nombreuses applications de type mobile nécessite de visualiser des collections de
données. Ces données sont généralement récupérées via des requêtes sur un serveur
SQL, voir sur une WebApi en technologie Rest.

Nous allons aborder une ressource permettant cette gestion qui est la ListView

<StackLayout>
<ListView x:Name="MyListView" ItemsSource="{Binding
Items}">
<[Link]>
<DataTemplate>
<ViewCell>
<Label Text="{Binding name}"></Label>
</ViewCell>
</DataTemplate>
</[Link]>
</ListView>
</StackLayout>
[Link] ListView
<ListView x:Name="MyListView" ItemsSource="{Binding
Items}">
La liste a sa source de données pour ses items liée à une ressource présente au niveau
code sous la forme d'une propriété

public UsersViewModel MyViewModel { get; set; }

public class UsersViewModel : INotifyPropertyChanged

La classe hérite d'une interface permettant la gestion de la mise à jour des ressources
graphiques liées à des propriétés dont le contenu viendrait à changer.
[Link] ListView
ObservableCollection<User> items;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<User> Items
{
get { return items; }
set { items = value;
OnPropertyChanged("Items"); }
}
protected void OnPropertyChanged(string item)
{
PropertyChangedEventHandler handler =
PropertyChanged;
if (handler != null)
{
handler(this, new
PropertyChangedEventArgs(item));
}
}
[Link] ListView
Nous ajoutons dans cette même classe la méthode permettant d'interroger d'une
façon asynchrone la méthode web pour récupérer une liste de contacts
public async Task InitUsers()
{
var httpClient = new HttpClient();
var url =
"[Link]
var result = await [Link](url);
if ([Link])
{
var data = await
[Link]();
[Link] =
[Link]<ObservableCollection<User>>(
data);
}
} classe User est créée sur base de la structure des données récupérées au format
La
JSON lors de la réponse à la requête.
[Link] ListView
Nous devons maintenant charger les données et les afficher. Une solution consiste à
démarrer le chargement lorsque la page de base aura été affichée. Nous
surchargeons donc une méthode correspondante de la page de contenu.

protected override async void OnAppearing()


{
[Link]();
await [Link]();
}
[Link] ListView
[Link] ListView
Nous tentons maintenant de récupérer les photos en provenance d'une autre
WebApi. Nous pourrions attendre que les photos soient chargées pour afficher tous
les contacts mais cela risque de rendre notre application moins réactive.

Si, pour chaque item à afficher, nous demandons la photo de façon synchrone, il en
sera de même au niveau de la lenteur d'affichage.

Il est donc important de prévoir un mécanisme de notification de sorte que l'affichage


se mette à jour lorsque la photo est disponible pour chacun des items. Nous allons
donc créer un modèle MVVM pour l'image
[Link] ListView
public class ImageModel : INotifyPropertyChanged
{
private ImageSource _ImageSrc;
public ImageSource ImageSrc
{
get { return _ImageSrc; }
set
{
_ImageSrc = value;
InvokePropertyChanged("ImageSrc");
}
}
}

Nous retrouvons bien l'assesseur set permettant, lors d'une mise à jour, d'effectuer la
notification pour la mise à jour de la ressource graphique liée. Cette classe devra
comprendre les méthodes suivantes
[Link] ListView
private void InvokePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new
PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;

Cette méthode permet de gérer les mécanismes de notification.


La méthode suivante est une méthode statique permettant de récupérer d'une
WebApi la photo correspondant à un identifiant donné. Cette méthode est
asynchrone (async et await).
[Link] ListView
public static async Task<ImageSource> GetImage(string id)
{
ImageSource imagesrc = null;
var httpClient = new HttpClient();
var url =
"[Link] + id + "/";
var result = await [Link](url);
if ([Link]) {
var data = await
[Link]();
var Photo =
[Link]<Photo>(data);
WebClient webClient = new WebClient();
byte[] imageBytes = await
[Link]([Link]);
imagesrc = [Link](() => new
MemoryStream(imageBytes));}
return imagesrc;
}
[Link] ListView
L'idée dans cet exemple est de charger les noms, de les afficher et de façon
asynchrone charger la photo pour chaque item.

Lorsque un objet de la classe User est créé, nous démarrerons la récupération de la


photo. Nous ajouterons donc le code suivant dans la classe User

public int id
{
get { return _id; }
set {
this._id = value;
Action LoadImage = async () =>
{
[Link] = await
[Link]([Link]());
};
LoadImage();
}
}
[Link] ListView
[Link] ListView - Swipe
Un swipe (geste de balayage) survient lorsqu'un doigt est déplacé sur l'écran
horizontalement ou verticalement et est souvent utilisé pour notamment naviguer
dans le contenu d'une page

Dans notre exemple, nous allons aborder deux cas:

- Celui où le swipe vertical permet de rafraîchir la liste


- Celui du swipe horizontal pour par exemple supprimer un des items de la liste

<ListView x:Name="MyListView"
ItemsSource="{Binding Path=[Link]}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding [Link]}"
IsRefreshing="{Binding [Link]}">

La propriété IsPullToRefreshEnabled permet d'activer la fonctionnalité du


swipe vertical.
[Link] ListView - Swipe
public Command RefreshUsersCommand{ get; private set; }

public UsersViewModel()
{
RefreshUsersCommand = new Command(RefreshUsersList);
}

private async void RefreshUsersList()


{
await InitUsers();
}

La propriété IsRefreshing="{Binding [Link]}" permet


de gérer l'icône indiquant que le rafraîchissement est en cours ou est terminé
[Link] ListView - Swipe
public bool _IsBusy=false;
public bool IsBusy
{
get { return _IsBusy; }
set
{
_IsBusy = value;
OnPropertyChanged("IsBusy");
}
}

Une fois le traitement terminé, il est important de placer la propriété à la valeur false

public async Task InitUsers()


{
//traitement effectué
[Link] = false;
}
[Link] ListView - Swipe
Pour le balayage horizontal, les choses sont peut-être moins simples. Apple a apporté
le swipe horizontal pour gérer notamment l'effacement tandis que Xamarin estime
que pour Android, le menu contextuel doit apparaître avec un toucher long.
Abordons la méthode proposée par Xamarin

<ViewCell>
<[Link]>
<MenuItem Text="Effacer"
Command="{Binding SwipeActionCommand,
Source={x:Reference Name=MyPage}}"
CommandParameter="{Binding .}"></MenuItem>
</[Link]>
</ViewCell>

Nous devons maintenant implémenter le code permettant l'implémentation de la


méthode liée à la commande
[Link] ListView - Swipe
public partial class MainPage : ContentPage
{
public Command SwipeActionCommand { get; private
set; }
public MainPage()
{
SwipeActionCommand = new Command(SwipeAction);
}

private async void SwipeAction()


{
await DisplayAlert("Alert", "Display Alert",
"OK");
}
}
[Link] ListView - Swipe

Vous aimerez peut-être aussi