Traduction▲
Cet article est la traduction la plus fidèle possible de l'article original de Josh Smith, A Guided Tour of WPF - Part 2 (Layout).
I. Introduction▲
Ceci est le deuxième article d'une série d'introduction à Windows Presentation Foundation. Dans l'article précédent, nous avons parlé de XAML et de la façon dont il est utilisé dans le développement d'une application WPF. Cet article aborde le riche support des panneaux de disposition dans WPF et comment ils sont utilisés dans l'application WPF Horse Race (disponible en téléchargement dans le premier article de la série).
Cet article ne cherche pas à fournir une description encyclopédique de tout le système de disposition de WPF. La documentation du SDK Windows fournit déjà des informations très complètes sur la manière d'utiliser et d'étendre le système de disposition de WPF, les répéter ici n'apporterait donc rien. Au lieu de ça, nous allons brièvement couvrir les bases et examiner comment l'application WPF Horse Race utilise les deux panneaux de disposition les plus courants : Grid et StackPanel.
II. Contexte▲
Le développement traditionnel d'interfaces graphiques pour les applications de bureau se base essentiellement sur le positionnement absolu des éléments visuels, c'est-à-dire l'affectation de propriétés sur les contrôles pour gérer leur position et leur taille. Il y a des concepts de plus haut niveau qu'on peut utiliser pour créer facilement des IHM qui s'adaptent à la taille de la fenêtre quand celle-ci est redimensionnée, comme le docking et l'ancrage des contrôles dans leur conteneur.
Cependant, dans Windows Forms 2.0 il y avait encore beaucoup de choses qui laissaient à désirer en ce qui concerne la disposition automatique de l'IHM. WPF gère très bien ce type de problématique, en empruntant certains des meilleurs concepts de disposition du monde HTML.
III. Disposition par panneaux▲
La classe Panel est la base abstraite pour tous les panneaux de disposition en WPF. Elle a une propriété Children qui contient des références à tous les UIElements enfants du panneau. Si vous ajoutez un élément aux enfants d'un panneau, la taille et/ou la position de l'élément seront gérées par le panneau.
Toutes les classes héritées de Panel, sauf une, gèrent le positionnement automatique de leurs enfants ; Canvas est l'exception à cette règle. Cela signifie en gros que si la taille de la fenêtre change, les panneaux vont automatiquement modifier la position de leurs éléments enfants. Certains panneaux, comme DockPanel ou Grid, peuvent aussi affecter la taille de leurs enfants. Ce comportement est utile quand vous voulez que des éléments visuels occupent autant d'espace que possible à l'écran, par exemple pour afficher des photos ou un graphique.
Si vous voulez en savoir plus sur les panneaux intégrés à WPF et les fonctionnalités qu'ils proposent, consultez la section Liens externes à la fin de l'article pour plus d'informations.
IV. Paramètres de disposition attachés▲
Les architectes de WPF ont décidé que puisque le système de disposition est extensible (c'est-à-dire que vous pouvez créer des classes dérivées de Panel), il fallait un moyen flexible de communiquer les paramètres de disposition entre les panneaux et leurs enfants. Avoir toutes les propriétés liées à la disposition dans une classe de base comme UIElement polluerait l'API et limiterait les possibilités de créer des panneaux personnalisés (on ne peut pas ajouter de propriétés à la classe UIElement). En bref, il fallait un moyen de définir des propriétés de disposition pour un élément visuel dans un panneau sans que cet élément ait besoin de connaître le panneau ou ses propriétés.
Ce problème a été résolu par l'introduction de propriétés attachées dans le framework WPF. Une propriété attachée peut être affectée sur n'importe quel objet ; celui-ci n'a pas besoin d'exposer la propriété qui est affectée. Par exemple :
<DockPanel>
<Button DockPanel.
Dock
=
"Left"
>
Alf Was Here</Button>
</DockPanel>
Le XAML ci-dessus met un bouton dans un DockPanel. Le bouton est collé au bord gauche du DockPanel parce que la propriété attachée Dock est définie à la valeur 'Left' de l'énumération Dock.
Pour plus d'informations sur le fonctionnement des propriétés attachées, consultez les pages mentionnées dans la section Liens Externes à la fin de l'article. Dans la section suivante, nous verrons les propriétés attachées en action.
V. Comment l'application WPF Horse Race utilise les panneaux▲
L'application WPF Horse Race utilise explicitement deux panneaux de disposition : Grid et StackPanel. Je précise « explicitement » parce qu'il est tout à fait possible que les contrôles utilisés dans l'application utilisent eux-mêmes d'autres panneaux que ces deux-là. En fait, une application WPF relativement simple contiendra généralement de nombreux panneaux, petits ou grands.
Jetons un coup d'œil à une version simplifiée du XAML de la fenêtre principale :
<Window>
<Grid>
<Grid.Background>
<ImageBrush
ImageSource
=
"Resources/Background.jpg"
Opacity
=
"0.25"
/>
</Grid.Background>
<Grid.RowDefinitions>
<!-- The top row is for the race track. -->
<RowDefinition
Height
=
"*"
/>
<!-- The bottom row is for the command strip. -->
<RowDefinition
Height
=
"Auto"
/>
</Grid.RowDefinitions>
<!-- The 'Race Track' area. -->
<ItemsControl Grid.
Row
=
"0"
... />
<!-- The 'Command Strip' area -->
<Border Grid.
Row
=
"1"
>
<Grid>
<StackPanel
Orientation
=
"Horizontal"
VerticalAlignment
=
"Center"
>
<TextBlock
Margin
=
"10,4"
>
Rotation: </TextBlock>
<Slider ... />
<TextBlock ... />
<TextBlock>
degrees</TextBlock>
</StackPanel>
<TextBlock
HorizontalAlignment
=
"Right"
Margin
=
"10,4"
>
<Hyperlink>
Start new race</Hyperlink>
</TextBlock>
</Grid>
</Border>
</Grid>
</Window>
Le XAML ci-dessus contient deux Grids et un StackPanel. Le diagramme ci-dessous montre les relations dans l'espace entre ces panneaux et les éléments qu'ils contiennent :
V-A. La disposition générale▲
La grille la plus à l'extérieur dans la fenêtre est coloriée en rouge. Remarquez qu'elle a deux lignes, séparées dans le diagramme ci-dessus par une ligne noire. Ces deux lignes ont été déclarées avec le balisage suivant :
<Grid.RowDefinitions>
<!-- The top row is for the race track. -->
<RowDefinition
Height
=
"*"
/>
<!-- The bottom row is for the command strip. -->
<RowDefinition
Height
=
"Auto"
/>
</Grid.RowDefinitions>
La hauteur de la première ligne est définie comme '*', ce qui signifie qu'elle essaiera d'être aussi haute que possible. La hauteur de la seconde ligne est définie comme 'Auto', de façon à ce qu'elle prenne la taille des éléments qu'elle contient. Cette configuration est pertinente parce que la barre de commande en bas de la fenêtre doit occuper juste assez d'espace pour être entièrement visible. Le reste de l'espace disponible doit être laissé à la « piste de course » au-dessus.
Remarquez que la hauteur des lignes n'est pas définie à une valeur numérique. La propriété Height peut être définie à une valeur numérique si nécessaire, mais il vaut généralement mieux laisser la classe Grid gérer autant de calculs de dimensions que possible. Cela permet à la grille de redimensionner intelligemment les lignes selon les besoins.
Voyons maintenant comment indiquer dans quelle ligne nous voulons placer les éléments visuels. La classe Grid expose plusieurs propriétés attachées, dont l'une est appelée Row. Voilà comment cette propriété attachée est utilisée :
<!-- The 'Race Track' area. -->
<ItemsControl Grid.
Row
=
"0"
... />
<!-- The 'Command Strip' area -->
<Border Grid.
Row
=
"1"
>
...</Border>
Il n'est pas indispensable de définir la propriété attachée Row sur l'élément ItemsControl parce que la valeur par défaut de cette propriété est zéro. En revanche, il faut la définir sur la Border de façon à ce qu'elle ne se superpose pas avec l'ItemsControl sur la première ligne.
V-B. Positionnement des éléments dans un panneau▲
Il y a deux façons courantes d'ajuster la position des éléments dans un panneau. L'une est de définir la propriété Margin de l'élément, l'autre est de jouer sur les propriétés HorizontalAlignment et/ou VerticalAlignment.
On peut voir l'utilisation de ces deux techniques sur le TextBlock qui contient le lien hypertexte sur la droite de la barre de commande :
<TextBlock
HorizontalAlignment
=
"Right"
Margin
=
"10,4"
>
<Hyperlink>
Start new race</Hyperlink>
</TextBlock>
Définir la propriété HorizontalAlignment à 'Right' a pour effet de « pousser » le TextBlock sur le côté droit de la grille. Définir sa propriété Margin à "10,4" est un raccourci pour dire qu'il doit y avoir au moins 10 pixels indépendants du périphérique (DIP, Device Independent Pixel) de marge à gauche et à droite de l'élément, et au moins quatre DIP de marge au-dessus et en dessous.
L'effet final de ces deux propriétés est que le lien hypertexte sera affiché sur la droite de la grille, mais avec un peu d'espace entre son bord droit et le bord droit de la grille. Le concept à retenir de ceci est que les panneaux vont s'occuper des « grandes lignes » du positionnement des éléments enfants, mais que ces derniers peuvent apporter la « touche finale » pour se positionner exactement là où ils doivent se trouver.
VI. Liens externes▲
Remerciements▲
Je tiens ici à remercier Josh Smith pour son aimable autorisation de traduire l'article, ainsi que Karzoff pour la relecture orthographique.