Les collections
5. Créer ses propres collections par du code
Il y a la collection Controls, créée et gérée automatiquement par VB, avec toutes les limites que nous venons de découvrir. Mais il existe aussi la possibilité de créer ses propres collections par du code. Bien
que cela soit un peu fastidieux, c'est parfois le seul moyen de gérer correctement certains problèmes.
5.1 Déclarer une collection
La première chose à faire sera de déclarer la collection, en lui donnant un nom (exactement comme on déclare une variable, ou un tableau). Par exemple :
Dim Ensemble as New Collection()
5.2 Remplir et vider une collection
Ensuite, il va falloir entrer dans cette collection, un par un, tous les éléments qui devront en faire partie, via la méthode Add. Par exemple :
Ensemble.Add(Me.Textbox1) Ensemble.Add(Me.Textbox2) Ensemble.Add(Me.Label5)
etc.
Disons tout de suite qu'on peut, de même, retirer un contrôle d'une collection par la méthode Remove : Ensemble.Remove(Me.Label5)
Arrivés à ce stade, nous savons donc gérer comme bon nous semble les membres d'une collection. Cela nous permet notamment de pouvoir procéder sans problèmes à des balayages systématiques (par exemple pour initialiser les valeurs de toute une série de contrôles, pour les rendre visibles ou invisibles, etc.). Cela nous permet également de désigner chaque contrôle membre de notre collection par son indice dans cette
collection, exactement comme nous le faisions avec la collection prédéfinie Controls. Enfin... presque !
Remarque bonne pour la santé mentale :
Les concepteurs de Visual Basic .Net ont décidé que si les indices des collections prédéfinies, telle Controls, commençaient en toute logique à zéro, les indices des collections créées par le programmeur
commenceraient quant à eux à 1 !
Si le gars de chez Microsoft dont j'ai parlé tout à l'heure m'appelle, tant qu'il y est, qu'il prépare aussi un argumentaire pour m'expliquer cela. Et qu'il fasse preuve d'imagination...
5.3 "Brancher" les événements sur une procédure unique
Passons. Un autre avantage considérable de disposer de tableaux de contrôles, était de pouvoir traiter un même événement survenant aux différents membres du tableau avec une seule procédure. Dans l'état
actuel de nos connaissances, c'est certes possible, via l'instruction Handles qui figure dans les titres des procédures : il suffit de faire suivre cette instruction Handles de la liste complète des membres de la
collection. C'est d'ailleurs cette technique que nous avons déjà eu l'occasion d'utiliser dans plusieurs exercices, sans même pour autant avoir créé de collection. Toutefois, cette combine a des limites :
dans le cas d'un ensemble formé de très nombreux contrôles, il va s'avérer infernal de devoir énumérer à la main tous ces contrôles après l'instruction Handles (pensez au démineur de Windows,
dont le plateau de jeu est formé d'un damier de boutons pouvant compter plusieurs centaines d'exemplaires !)
même si nous n'avons pas encore étudié cette situation, les contrôles ne sont pas toujours créés au départ du programme, via la fenêtre Design. Dans bien des cas, on va souhaiter créer des contrôles par du code, en cours d'exécution. Dès lors, comment rattacher les événements survenant à
ces contrôles - qui n'existent pas encore - à telle ou telle procédure événementielle, lorsqu'on écrit celle-ci ?
La parade à ces problèmes tient dans la possibilité de rattacher par du code, donc en cours d'exécution, tel événement survenant à tel contrôle, à telle procédure existante. C'est le sens de l'instruction
AddHandler, qui donnera par exemple : AddHandler Button2.Click AddressOf MiseAJour
Dans cet exemple, MiseAJour est le nom de la procédure sur laquelle nous programmons le "branchement" de l'événement Button2.Click.
Nous sommes presque au bout de nos peines. Nous savons à présent :
regrouper les contrôles de notre choix dans une collection parcourir cette collection pour la traiter de manière systématique
associer l'ensemble des contrôles d'une collection à une seule procédure événementielle, afin d'en simplifier la gestion.
5.4 Indentifier le contrôle qui a déclenché l'événement
Il ne nous reste plus qu'un seul souci, mais de taille. Imaginons que nous ayons 125 boutons sur notre Form, sur lequel un clic mène infailliblement à une procédure unique. Comment faire pour récupérer, au sein
de cette procédure, le bouton précis qui a provoqué l'événement (ce qui est souvent indispensable) ? Nous disposons certes du paramètre Sender, que nous avons déjà utilisé lors d'exercices précédents. Sender est
Il y a alors de fortes chances pour que nous ayons besoin de savoir à quel indice dans la collection correspond le contrôle désigné par cette variable Sender. Pour cela, nous pouvons utiliser la méthode
IndexOf, qui renvoie l'indice de n'importe quel contrôle au sein de n'importe quelle collection... enfin, presque. J'y reviens dans un instant. Ainsi, imaginons que nous ayons créé un Panel comprenant une série de
100 boutons, pour lesquels une boucle a habilement renvoyé l'événement Click vers une procédure Yaclic. Supposons enfin que nous souhaitions afficher en titre de la Form l'indice du bouton sur lequel l'utilisateur
vient de cliquer. La procédure Yaclic aurait alors la tête suivante :
Private Sub Yaclic(ByVal sender As System.Object, ByVal e As System.EventArgs) Dim i As Integer
i = Panel1.Controls.IndexOf(sender) Me.Text = i
End Sub
Cette technique, simple et efficace, ne fonctionnera toutefois pas au sein des collections que nous aurons créées et remplies par du code, les collections créées par le programmeur ignorant la méthode
IndexOf ! Pour celles-ci, il faudra avoir recours à une voie détournée : programmer une boucle qui compare, par exemple, la propriété Name de chaque membre de la collection Macollec avec celui du sender, sur le
modèle suivant :
Private Sub Yaclic(ByVal sender As System.Object, ByVal e As System.EventArgs) Dim i As Integer
For i = 1 to Macollec.Count
If Macollec.Item(i).Name = sender.Name Then Me.Text = i
Endif Next i
End Sub
En conclusion : VB.Net permet de faire tout ce que nous permettaient les tableaux de contrôles des versions précédentes de VB, mais au prix d'un code nettement plus compliqué. Et par-dessus le marché, au
lieu d'établir une règle simple fonctionnant dans toutes les situations, les gars de chez Microsoft se sont amusés à multiplier les exceptions. Comme quoi, les Shadoks ont incontestablement inspiré Bill Gates lorsqu'ils proclamaient solennellement : "En essayant continuellement, on finit par réussir. Donc : plus ça
rate, plus on a de chance que ça marche"