Utilisation du contrôle Panel en WinForms

Visual_Studio_2013_Logo.svg

Dans cet article, je vous propose de voir comment gérer la mise en forme d'une Windows Form, par l'utilisation du contrôle
Panel et la propriété Dock.


Pour cela, nous aurons besoin d'une fenêtre disponible dans Visual Studio : la fenêtre Document Outline (Structure
du Document en version Française).

structure_menu
outlineCette fenêtre permet de voir l'encapsulation de tous les contrôles présents dans la WinForm, ce qui est indispensable pour gérer la mise en forme.

 

 

 

 

 

outline_navElle permet aussi de changer l'encapsulation des différents contrôles soit en mode "Drag and drop", soit avec les flèches de navigation.

 

 

 

 

En mode Designer, si on prend un contrôle et qu'on le pose, il va automatiquement être encapsulé dans le contrôle
où il a été posé. La fenêtre Document Outline va donc permettre de faire sortir les contrôles des conteneurs :

over
Propriété Dock :
Il faut savoir que la propriété Dock est héritée de la classe Control, ce qui veut dire que tous les contrôles WinForm (contenus dans le namespace System.Windows.Forms) pourront utiliser cette propriété.
La propriété Dock permet d'amarrer un contrôle à un côté de son conteneur.

dock
De ce fait, un contrôle avec la propriété DockStyle.Top sera amarré au bord haut de son conteneur. Pour se faire, le contrôle en question va prendre toute la largeur possible (pas besoin de gérer la largeur lors d'un redimensionnement de la fenêtre par l'utilisateur) et la hauteur du contrôle sera a définir car elle sera, dans l'absolu, fixe (on pourra la modifier en ligne de code si on le souhaite).

size1 size2
Par extension, un contrôle avec la propriété DockStyle.Bottom sera amarré au bord bas de son conteneur, un contrôle avec la propriété DockStyle.Left sera amarré au bord gauche de son conteneur, et ainsi de suite.
La place prise par chaque contrôle est réservée, de sorte à ce que les contrôles suivants amarrés soient générés en fonction des précédents contrôles.

left1 left2 left3

Avant d'expliquer le fonctionnement de DockStyle.Fill (remplissage), on va d'abord voir le principe de pile de contrôles :
Les contrôles mis en place dans le Designer sont contenus dans la collection de contrôles du conteneur (MonConteneur.Controls de type ControlCollection) gérés par la règle du LIFO ("Last In, First Out" ou "Dernier entré, premier sorti").

Lifo

(Source : Wikipedia)

En effet, si on parcourt la liste Controls de manière naturelle, on va d'abord accéder au dernier contrôle créé pour finir par le premier contrôle créé. On peut visualiser cette pile dans la fenêtre Document Outline présentée précédemment. Ce cheminement est identique lors de la génération des contrôles à l'écran.
Prenons en exemple 3 contrôles définis comme DockStyle.Top : pour que les Panel soient affichés dans l'ordre 1, 2 et 3 (de haut en bas), il faut que les contrôles dans la pile soient empilés de sorte que le contrôle 1 soit généré en premier (donc sur le dessus de la pile dans le cas du LIFO).

pile
La compréhension de la pile va permettre d'utiliser la propriété DockStyle.Fill avec plus de finesse.
La propriété DockStyle.Fill permet à un contrôle de remplir l'espace disponible de son conteneur.
Contrairement à toutes les autres options possibles pour Dock, DockStyle.Fill ne réserve pas la place utilisée pour générer le contrôle.
Attention, il ne peut y avoir qu'un seul contrôle avec la propriété DockStyle.Fill dans un conteneur.
Exemple 1 : Dans cet exemple, le contrôle avec la propriété DockStyle.Fill est généré en dernier. La place utilisée pour ce contrôle est donc l'espace restant après avoir généré les deux premiers panels qui sont en DockStyle.Top.

fill1

Exemple 2 : Dans cet exemple, le contrôle avec la propriété DockStyle.Fill est généré en deuxième. La place utilisée pour ce contrôle est donc l'espace restant après avoir généré le premier panel en DockStyle.Top. Le deuxième panel en DockStyle.Top est généré après avoir calculé la place à utiliser (qui n'est pas réservée) pour le panel en DockStyle.Fill. Ces deux panels vont donc se chevaucher.

fill2

 

Le contrôle Panel et la propriété AutoScroll (affichage de la barre de défilement) :
Premier point important : L'AutoScroll ne fonctionne pas pour un contrôle en DockStyle.Fill. Il faut définir les propriétés MinimumSize et AutoScrollMinSize pour avoir accès aux barres. Mais là encore, le fonctionnement est loin d'être celui  désiré : s'il y a d'autres contrôles amarrés présents dans le conteneur, le contrôle en DockStyle.Fill disparaîtra quand le redimensionnement fera sortir ce contrôle du conteneur (pour rappel, la place prise par ce contrôle n'est pas réservée).

 

Pour avoir un contenu à taille variable (en fonction de la taille de la fenêtre en général), il va falloir modifier via le code la taille du Panel plutôt que d'utiliser le DockStyle.Fill.
Voici un exemple de mise en place :

Structure : 3 zones de contenu dont un occupera la place restante et 1 zone dédiée aux boutons de validation/annulation.

responsive1

On a le conteneur pnlContenuFill en DockStyle.Fill qui contiendra nos 3 zones de contenu et le conteneur pnlBoutonsBot en DockStyle.Bottom qui contiendra nos boutons.

responsive2

En ce qui concerne le conteneur pnlContenuFill, voici les propriétés pour le fonctionnement correct du redimensionnement :
- La propriété AutoScroll à True pour permettre l'utilisation de ScrollBars.
- La propriété AutoScrollMinSize pour permettre l'utilisation de la ScrollBar horizontale (souvenez-vous, un contrôle en DockStyle.Top prendra automatiquement tout la largeur).
Attention, l'apparition des ScrollBars se fait "par-dessus" le contrôle, il faut donc prévoir la place de ces ScrollBars et éviter de cacher des contrôles.

 

 

 

responsive3Dans le conteneur pnlContenuFill on va mettre nos 3 zones de contenu : 3 contrôles de type Panel en DockStyle.Top.
Pour le contrôle qui va être redimensionné, il va falloir lui donner une taille minimum (via la propriété MinimumSize) pour qu'on puisse utiliser les ScrollBars.

 

 

 

 

Dans le code, sur l'événement SizeChanged de la Form, on va rajouter la partie suivante :

private void Form1_SizeChanged(object sender, EventArgs e)
{
    // Redimensionne le Panel de contenu dynamique
    pnlFill.Height = pnlContenuFill.Height - (pnlTop1.Height + pnlTop2.Height);
}

visuel visuel2

Voici le rendu lors de différents redimensionnements. Comme vous pouvez le voir, le texte en "BAS" du 3ème Panel est resté à sa position initiale.

Pour le positionnement du contenu, on peut utiliser (à ma connaissance) 2 techniques différentes :

anchorLa plus simple est l'utilisation de la propriété Anchor qui permet de fixer la distance entre un contrôle et les bords de son conteneur. Les contrôles sont créés par défaut avec un Anchor Top et Left : le contrôle sera toujours à la même distance du bord haut et du bord gauche de son conteneur, quelle que soit la taille du conteneur. On peut définir la propriété Anchor pour chaque contrôle ou bien tout regrouper dans un Panel.

 

 

La deuxième méthode, plus contraignante, consiste à utiliser la propriété Dock pour plusieurs contrôles imbriqués : On met un contrôle Panel en DockStyle.Bottom qui encapsule un autre contrôle Panel en DockStyle.Right qui contiendra les différents contrôles à afficher. L'utilisation de la fenêtre Document Outline permettra d'avoir une hiérarchie claire dans l'encapsulation des contrôles.

 

Pour conclure, l'utilisation du contrôle Panel et de la propriété Dock permet d'avoir des fenêtres "responsive", jusqu'à une certaine limite. On peut pousser la mise en page encore plus loin en modifiant les coordonnées des contrôles dans leur conteneur lors de l'événement SizeChanged de la Form.
Je conseille fortement de donner une taille minimale à la Form elle-même pour éviter les affichages de ce genre :

last

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.