Recréons la ComboBox pour Windows Phone

Formation

À Paris

Prix sur demande

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Description

  • Typologie

    Formation

  • Lieu

    Paris

Grâce à cette formation vous pourrez acquérir les connaissances nécessaires qui vous permettrons d’ajouter des compétences à votre profil et obtenir de solides aptitude qui vous offriront de nombreuses opportunités professionnelles.

Les sites et dates disponibles

Lieu

Date de début

Paris ((75) Paris)
Voir plan
7 Cité Paradis, 75010

Date de début

Consulter

Questions / Réponses

Ajoutez votre question

Nos conseillers et autres utilisateurs pourront vous répondre

À qui souhaitez-vous addresser votre question?

Saisissez vos coordonnées pour recevoir une réponse

Nous ne publierons que votre nom et votre question

Les Avis

Le programme

Introduction du cours

En effectuant le portage d’une application Android vers Windows Phone, je me suis heurté à une difficulté à laquelle je ne m’attendais vraiment pas : l’absence d’équivalent au Spinner d’Android ou à la ComboBox de Silverlight. Je me suis donc lancé dans la création de mon propre composant graphique, et ce travail a été un très bon prétexte pour explorer plus à fond les possibilités offertes par Silverlight, et plus précisément le principe du DataBinding.

Une ComboBox est un contrôle visuel qui permet de sélectionner une valeur dans une liste déroulante présentant les choix possibles. Ce contrôle est présent dans la plupart des librairies ou frameworks d’affichage, parfois sous d’autres noms. Certains considèrent ce composant comme inadapté au développement mobile, car difficile à utiliser sur de petits écrans. Dans certains cas, il reste pourtant la meilleure solution.

Cet article va donc retracer étape par étape ce développement, en présentant à chaque fois les mécanismes utilisés.

Contexte et objectifs

Voici des exemples du type de composant ComboBox que nous allons créer.

Le composant "Spinner" d'Android (source) et la ComboBox de Silverlight(source)

Une recherche rapide sur Internet montre que beaucoup de développeurs rencontrent ce problème. Deux approches sont généralement retenues :

  • Utiliser une ComboBox en l‘ajoutant directement depuis le XAML décrivant la page, puis modifier le style. Le composant ComboBox existe bel et bien, même si l’éditeur d’interface de Visual Studio ne le propose pas, mais n’est pas customisé pour s’intégrer dans une interface Windows Phone. Il est alors possible de complètement redéfinir le style pour l’adapter à l’application. La démarche pour y parvenir est présentée sur cette page.

  • Utiliser le composant « ListPicker » du Windows Phone Toolkit. Il reproduit exactement le comportement voulu, avec quelques spécificités, notamment le passage en plein écran à partir d’un certain nombre d’entrées. Cet article offre un aperçu rapide de son utilisation.

La première solution me parait lourde à mettre en place et délicate à réutiliser sur d’autres projets. La deuxième est intéressante, mais le passage en plein écran au-delà de trois éléments ne me satisfait pas. Je trouve qu’il rend la navigation moins fluide dans le cas de nombreuses ComboBox les unes après les autres, et ce composant s’intègre mal dans la structure de ma page.

J’ai donc choisi une troisième approche, qui consiste à créer ma propre ComboBox.

L’application de test

Pour mieux comprendre le besoin et illustrer la création du composant, nous allons nous intéresser à une application minimaliste mettant en jeu de nombreuses ComboBox. Elle permettra le remplissage, pour différents vols, de leurs aéroports de départ et d’arrivée.

Les vols devront être affichés dans une ListBox, les uns en dessous des autres, comme indiqué sur la figure suivante :

Ecran "Liste des vols"

Les noms des aéroports seront indiqués dans des ComboBox pour permettre de les modifier.

Structure de l’application

La solution Visual Studio comprendra deux projets :

  • CombinedComboBox, de type librairie pour Windows Phone, qui contiendra le composant développé,

  • CombinedComboBoxTestApp, de type application pour Windows Phone, qui contiendra l’application de test et référencera le premier projet.

L’application de test sera constituée d’une vue principale MainPage.xaml, d’un UserControl FlightPresenter.xaml servant à représenter un élément de la liste, et d’une classe DataStore servant à fournir les données.
Nous rajouterons également un fichier AirportToStringConverter.cs dont l’utilité sera présentée plus tard.

Découpage de l'écran "Liste des vols"

Le fichier DataStore.cs contient la classe DataStore qui expose trois listes distinctes :

  • Une liste des vols,

  • Une liste d’aéroports français,

  • Une liste d’aéroports européens

Toujours dans le fichier DataStore.cs, nous écrivons deux autres classes, nécessaires pour représenter les données :

public class Airport { public string City { get; set; } public string Name { get; set; } public int RunwayCount { get; set; } public Airport(string city, string name, int runwayCount) { City = city; Name = name; RunwayCount = runwayCount; } public bool Equals(Airport a) { return Name == a.Name; } } public class Flight { public int FlightNumber { get; set; } public Airport Destination { get; set; } public Airport Leaving { get; set; } public Flight(int number, Airport leaving, Airport destination) { FlightNumber = number; Destination = destination; Leaving = leaving; } }

Le code de la page principal est très simple et n’évoluera pas dans la suite :

<phone:PhoneApplicationPage […] DataContext="{Binding Source={StaticResource DataStore}}"> <Grid x:Name="LayoutRoot" Background="WhiteSmoke"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Border Grid.Row="0" Margin="10" Padding="0,0,0,4" BorderThickness="0,0,0,1" BorderBrush="Firebrick" > <Button Content="CombinedComboBox test app" Command="{Binding ClickOnPageTitleCommand}" FontSize="30" Foreground="Black"/> </Border> <ListBox x:Name="FlightList" ItemsSource="{Binding Flights}" Grid.Row="1"> <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> </Style> </ListBox.ItemContainerStyle> <ListBox.ItemTemplate> <DataTemplate> <local:FlightPresenter DataContext="{Binding}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </phone:PhoneApplicationPage>

La commande ClickOnPageTitleCommand sera présentée plus loin dans le document, elle servira à des fins de test. Pour l’instant nous pouvons la créer, vide, dans notre DataStore :

private ICommand _clickOnPageTitleCommand; public ICommand ClickOnPageTitleCommand { get { return _clickOnPageTitleCommand ?? (_clickOnPageTitleCommand = new DelegateCommand(ClickOnPageTitle)); } } private void ClickOnPageTitle(){}

Reste le fichier FlightPresenter.xaml, qui instanciera les ComboBox. La structure de base est la suivante :

<UserControl […]> <UserControl.Resources> </UserControl.Resources> <Border BorderBrush="Gray" BorderThickness="0,0,0,1"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding FlightNumber}" Tap="OnFlightNameTaped" Foreground="Black" Margin="0,36,0,36" FontSize="26" Grid.Column="0" Grid.RowSpan="2" TextAlignment="Center"/> <TextBlock Foreground="Black" Margin=" 0,10,0,5" Text="dep." FontSize="26" Grid.Column="1" Grid.Row="0"/> <TextBlock Foreground="Black" Margin="0,5,0,10" Text="dest." FontSize="26" Grid.Column="1" Grid.Row="1"/> <!-- ComboBox pour la provenance --> <!-- ComboBox pour la destination --> </Grid> </Border> </UserControl>

Nous y retrouvons le champ FlightNumber de la classe Flight, affiché grâce à un Binding (dans l’extrait de code de MainPage.xaml plus haut, la ligne <local:FlightPresenter DataContext="{Binding}"/> dans le DataTemplate de la ListBox définissait le vol en cours d’affichage comme DataContext pour le FlightPresenter).

Il faudra également créer la méthode OnFlightNameTaped pour que ce code fonctionne :

private void OnFlightNameTaped(object sender, GestureEventArgs e) { DestinationComboBox.IsEnabled = !DestinationComboBox.IsEnabled; }

Il ne nous restera donc plus qu’à remplacer les deux commentaires dans le XAML par l’instanciation de nos ComboBox.

Résultat avec le ListPicker

Commençons dans un premier temps par tester le code avec le ListPicker du Windows Phone toolkit évoqué dans l’introduction. Nous ne listerons pour l'instant que les aéroports européens (mais non français). Le code remplaçant les annotations et l’application en résultant sont visibles ci-dessous :

<toolkit:ListPicker x:Name="LeavingComboBox" SelectedItem="{Binding Leaving}" ItemsSource="{Binding Source={StaticResource DataStore}, Path=EuropeanAirports}" FontSize="26" Margin="10,5" VerticalAlignment="Center" Grid.Column="2" Grid.Row="0"> <toolkit:ListPicker.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" TextTrimming="WordEllipsis"/> </DataTemplate> </toolkit:ListPicker.ItemTemplate> </toolkit:ListPicker> <toolkit:ListPicker x:Name="DestinationComboBox" SelectedItem="{Binding Destination}" ItemsSource="{Binding Source={StaticResource DataStore}, Path=EuropeanAirports}" FontSize="26" Margin="10,5" VerticalAlignment="Center" Grid.Column="2" Grid.Row="1"> <toolkit:ListPicker.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" TextTrimming="WordEllipsis"/> </DataTemplate> </toolkit:ListPicker.ItemTemplate> </toolkit:ListPicker>

Ouverture de ComboBox

On remarque sur la deuxième image comme la page se déforme pour permettre le déroulement de la liste. Sur la troisième image, en déroulant la liste en bas du téléphone, il est nécessaire de scroller pour voir la liste qui s’affiche hors de l’écran.

Pour obtenir le visuel ci-dessus il faut également ajouter un style aux ListPicker, comme indiqué ici, mais je ne présenterai pas ce code, trop long et non essentiel à la compréhension.

En ajoutant de nouveaux aéroports dans le DataStore, il est également possible d’observer le passage en mode plein écran.

On remarquera enfin que si la liste Flights contient des destinations qui ne sont pas dans la liste EuropeanAirports, une exception sera levée à l’exécution. Ce comportement peut être limitant dans certain cas. Imaginons par exemple que l’aéroport de Madrid soit en rénovation. Le personnel ne serait plus autorisé à créer de nouveaux vols en partance ou à destination de cet aéroport, il ne figurera donc pas dans la liste déroulante. Par contre, les vols qui avaient déjà été prévus pour cette destination seraient tout de même accueillis grâce à un dispositif spécial : Madrid doit donc pouvoir apparaître comme valeur sélectionnée sur ces vols. L’image ci-dessous illustre ce phénomène :

Valeur active non sélectionnable

Création de notre propre ComboBox

Nous allons maintenant remplacer le ListPicker utilisé dans cet exemple par notre propre composant, qui pourra :

  • S’afficher toujours par-dessus la page sans en modifier la disposition,

  • Se repositionner pour ne pas dépasser de la page,

  • Accepter des valeurs sélectionnées n’appartenant pas à la liste des valeurs sélectionnables,

  • Permettre de définir le mode d’affichage des éléments soit de manière classique avec des DataTemplates, soit en spécifiant un simple Converter pour offrir une syntaxe plus concise,

  • Accepter une valeur vide permettant d’annuler la sélection,

  • Concaténer plusieurs sources de données dans le menu déroulant

Le composant que nous allons réaliser permet d’obtenir le rendu suivant :

ComboBox à créer

On remarquera que la liste déroulante n’est pas alignée sur le champ, mais qu’elle se centre par rapport à la page. C’est un comportement que je trouve appréciable dans le cas d’une utilisation sur mobile, puisque cela permet de tirer partie de tout l’espace disponible, tout en conservant un menu façon pop-up plutôt qu’une nouvelle page plein écran. Il serait possible de modifier ce comportement, nous en reparlerons dans la conclusion.

Nous allons suivre les étapes suivantes pour la réalisation du composant :

  • Etape 1 : Création de la liste déroulante</lien>

  • Etape 2 : Ajout des éléments à la ComboBox

  • Etape 3 : Convertir les valeurs pour l’affichage

  • Etape 4 : Gestion des événements

  • Etape 5 : Ajout d’une valeur « vide »

  • Etape 6 : Ajout de listes multiples

  • Etape 7 : Personnaliser l’apparence de la ComboBox

Etape 1 : Création de la liste déroulante

Nous utiliserons un UserControl pour créer notre ComboBox, qui sera composé

  • d’un ContentControl affichant la valeur active,

  • d’un ContextMenu servant de liste déroulante.

L’intérêt du ContextMenu pour ce composant tient à ce qu’il s’affiche toujours au dessus des éléments de la page, sans impacter leur disposition. C’est le menu qui apparait par exemple lorsque vous effectuez un clic long sur une application installée :

ContextMenu...

Appeler le centre

Avez-vous besoin d'un coach de formation?

Il vous aidera à comparer différents cours et à trouver la solution la plus abordable.

Recréons la ComboBox pour Windows Phone

Prix sur demande