Dessiner des formes

Apprenez comment dessiner des formes, telles que des ellipses, des rectangles, des polygones et des chemins d'accès. La classe Path est le moyen de visualiser un langage de dessin basé sur des vecteurs assez complexe dans une interface utilisateur XAML ; par exemple, vous pouvez dessiner des courbes Bezier.

Deux ensembles de classes définissent une région d’espace dans l’interface utilisateur XAML : classes de forme et classes Geometry. La principale différence entre ces classes est qu’une forme a un pinceau associé à celui-ci et qu’elle peut être rendue à l’écran, et qu’une géométrie définit simplement une région d’espace et n’est pas rendue, sauf si elle permet de contribuer aux informations d’une autre propriété d’interface utilisateur. Vous pouvez considérer une forme comme un UIElement avec sa limite définie par une géométrie. Cette rubrique couvre principalement les classes Shape.

Les classes Shape sont Line, Ellipse, Rectangle, Polygon, Polyline et Path. Le chemin d’accès est intéressant, car il peut définir une géométrie arbitraire et la classe Geometry est impliquée ici, car il s’agit d’une façon de définir les parties d’un chemin d’accès.

UWP et WinUI 2

Important

Les informations et les exemples de cet article sont optimisés pour les applications qui utilisent le SDK d'application Windows et WinUI 3, mais qui s’appliquent généralement aux applications UWP qui utilisent WinUI 2. Consultez la référence API de la plateforme Windows universelle pour obtenir des informations et des exemples spécifiques à la plateforme.

Cette section contient les informations dont vous avez besoin pour utiliser le contrôle dans une application de la plateforme Windows universelle ou de WinUI 2.

Les API de ces formes existent dans l’espace de noms Windows.UI.Xaml.Shapes.

Remplissage et trait pour les formes

Pour qu’une forme s’affiche dans le canevas de l’application, vous devez associer un pinceau à celui-ci. Définissez la propriété Fill de la forme sur le pinceau souhaité. Pour plus d’informations sur les pinceaux, consultez Utilisation de pinceaux.

Une forme peut également avoir un trait, qui est une ligne dessinée autour du périmètre de la forme. Un trait nécessite également un pinceau qui définit son apparence et doit avoir une valeur non nulle pour StrokeThickness. StrokeThickness est une propriété qui définit l’épaisseur du périmètre autour du bord de la forme. Si vous ne spécifiez pas de valeur de pinceau pour Trait, ou si vous définissez StrokeThickness sur 0, la bordure autour de la forme n’est pas dessinée.

Ellipse

Un Ellipse est une forme avec un périmètre courbé. Pour créer un Ellipse de base, spécifiez une largeur, une hauteur et un pinceau pour le remplissage.

L’exemple suivant crée un Ellipse avec une largeur de 200 et une hauteur de 200, et utilise un SolidColorBrush couleur SteelBlue comme remplissage.

<Ellipse Fill="SteelBlue" Height="200" Width="200" />
var ellipse1 = new Ellipse();
ellipse1.Fill = new SolidColorBrush(Colors.SteelBlue);
ellipse1.Width = 200;
ellipse1.Height = 200;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(ellipse1);

Voici l’Ellipse rendu.

A rendered Ellipse.

Dans ce cas, l’Ellipse est ce que la plupart des gens considéreraient un cercle, mais c’est la façon dont vous déclarez une forme de cercle en XAML : utilisez un Ellipse avec une largeur et une hauteur égales.

Lorsqu’un Ellipse est positionné dans une disposition d’interface utilisateur, sa taille est supposée être identique à un rectangle avec cette largeur et cette hauteur ; la zone en dehors du périmètre n’a pas de rendu, mais fait toujours partie de sa taille d’emplacement de disposition.

Un ensemble de 6 éléments Ellipse fait partie du modèle de contrôle pour le contrôle ProgressRing, et 2 éléments concentriques Ellipse font partie d’un RadioButton.

Rectangle

Un rectangle est une forme à quatre côtés dont les côtés opposés sont égaux. Pour créer un rectangle de base, spécifiez une largeur, une hauteur et un remplissage.

Vous pouvez arrondir les angles d'un Rectangle. Pour créer des angles arrondis, spécifiez une valeur pour les propriétés RadiusX et RadiusY. Ces propriétés spécifient l’axe x et l’axe y d’un ellipse qui définit la courbe des angles. La valeur maximale autorisée de RadiusX est la largeur divisée par deux et la valeur maximale autorisée de RadiusY est la hauteur divisée par deux.

L’exemple suivant crée un rectangle avec une largeur de 200 et une hauteur de 100. Il utilise une valeur bleue de SolidColorBrush pour son remplissage et une valeur noire de SolidColorBrush pour son trait. On a mis le StrokeThickness sur 3. Nous définissons la propriété RadiusX sur 50 et la propriété RadiusY sur 10, ce qui donne aux angles arrondis rectangle.

<Rectangle Fill="Blue"
           Width="200"
           Height="100"
           Stroke="Black"
           StrokeThickness="3"
           RadiusX="50"
           RadiusY="10" />
var rectangle1 = new Rectangle();
rectangle1.Fill = new SolidColorBrush(Colors.Blue);
rectangle1.Width = 200;
rectangle1.Height = 100;
rectangle1.Stroke = new SolidColorBrush(Colors.Black);
rectangle1.StrokeThickness = 3;
rectangle1.RadiusX = 50;
rectangle1.RadiusY = 10;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(rectangle1);

Voici le rectangle rendu.

A rendered Rectangle.

Dans certains scénarios de définition de l'interface utilisateur, il est préférable d'utiliser une bordure plutôt qu'un rectangle. Si votre intention est de créer une forme de rectangle autour d’un autre contenu, il peut être préférable d’utiliser la bordure, car elle peut avoir du contenu enfant et sera automatiquement dimensionner autour de ce contenu, plutôt que d’utiliser les dimensions fixes pour la hauteur et la largeur comme Rectangle. Une bordure a également la possibilité d’avoir des angles arrondis si vous définissez la propriété CornerRadius.

En revanche, un rectangle est probablement un meilleur choix pour la composition de contrôle. Une forme Rectangle est vue dans de nombreux modèles de contrôle, car elle est utilisée comme composant « FocusVisual » pour les contrôles focusables. Chaque fois que le contrôle est dans un état visuel « Prioritaire », ce rectangle est rendu visible, dans d’autres états, il est masqué.

Polygon

Un polygone est une forme avec une limite définie par un nombre arbitraire de points. La limite est créée en connectant une ligne d’un point à l’autre, avec le dernier point connecté au premier point. La propriété Points définit la collection de points qui composent la limite. En XAML, vous définissez les points avec une liste séparée par des virgules. Dans code-behind, vous utilisez un PointCollection pour définir les points et ajouter chaque point individuel en tant que valeur point à la collection.

Vous n’avez pas besoin de déclarer explicitement les points tels que le point de départ et le point de terminaison sont tous deux spécifiés comme la même valeur de point. La logique de rendu d’un polygone suppose que vous définissez une forme fermée et connectera implicitement le point de terminaison au point de départ.

L’exemple suivant crée un polygone avec 4 points définis sur (10,200), (60,140), (130,140) et (180,200). Il utilise une valeur LightBlue de SolidColorBrush pour son remplissage et n’a pas de valeur pour trait afin qu’il n’ait pas de contour de périmètre.

<Polygon Fill="LightBlue"
         Points="10,200,60,140,130,140,180,200" />
var polygon1 = new Polygon();
polygon1.Fill = new SolidColorBrush(Colors.LightBlue);

var points = new PointCollection();
points.Add(new Windows.Foundation.Point(10, 200));
points.Add(new Windows.Foundation.Point(60, 140));
points.Add(new Windows.Foundation.Point(130, 140));
points.Add(new Windows.Foundation.Point(180, 200));
polygon1.Points = points;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(polygon1);

Voici le polygone rendu.

A rendered Polygon.

Conseil

Une valeur Point est souvent utilisée en tant que type en XAML dans les situations autres que la déclaration des sommets des formes. Par exemple, un point fait partie des données d’événement pour les événements tactiles. Vous pouvez donc savoir exactement où, dans un espace de coordonnées, l’action tactile s’est produite. Pour plus d’informations sur Point et sur la façon de l’utiliser en XAML ou en code, consultez la rubrique de référence de l’API pour Point.

Graphique en courbes

Une ligne est simplement une ligne dessinée entre deux points dans l’espace de coordonnées. Une ligne ignore toute valeur fournie pour Le remplissage, car elle n’a pas d’espace intérieur. Pour une ligne, veillez à spécifier des valeurs pour les propriétés Stroke et StrokeThickness, car sinon, la ligne ne s’affiche pas.

Vous n’utilisez pas de valeurs point pour spécifier une forme De ligne, au lieu de cela, vous utilisez des valeurs doubles discrètes pour X1, Y1, X2 et Y2. Cela permet un balisage minimal pour les lignes horizontales ou verticales. Par exemple, <Line Stroke="Red" X2="400"/> définit une ligne horizontale de 400 pixels. Les autres propriétés X,Y sont 0 par défaut. Par conséquent, en termes de points, ce code XAML dessinerait une ligne à partir de (0,0)(400,0). Vous pouvez ensuite utiliser un TranslateTransform pour déplacer la ligne entière, si vous souhaitez qu’elle commence à un point autre que (0,0).

<Line Stroke="Red" X2="400"/>
var line1 = new Line();
line1.Stroke = new SolidColorBrush(Colors.Red);
line1.X2 = 400;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(line1);

Polyline

Une polyligne est similaire à un polygone dans lequel la limite de la forme est définie par un ensemble de points, sauf que le dernier point d’une Polyline n’est pas connecté au premier point.

Remarque

Vous pourriez explicitement avoir un point de départ et un point d'arrivée identiques dans le jeu de points pour la polyligne, mais dans ce cas, vous auriez probablement pu utiliser un Polygone à la place.

Si vous spécifiez un remplissage d’une polyligne, le remplissage peint l’espace intérieur de la forme, même si le point de départ et le point de fin du jeu Points pour la polyligne ne se croisent pas. Si vous ne spécifiez pas de remplissage, la ligne Polyline est similaire à ce qui aurait été rendu si vous aviez spécifié plusieurs éléments de ligne individuels où les points de début et les points de fin des lignes consécutives se croisaient.

Comme pour un polygone, la propriété Points définit la collection de points qui composent la limite. En XAML, vous définissez les points avec une liste séparée par des virgules. Dans code-behind, vous utilisez un PointCollection pour définir les points et ajouter chaque point individuel en tant que structure point à la collection.

Cet exemple crée une polyline avec quatre points définis sur (10,200), (60,140), (130,140) et (180,200). Un trait est défini, mais pas un remplissage.

<Polyline Stroke="Black"
          StrokeThickness="4"
          Points="10,200,60,140,130,140,180,200" />
var polyline1 = new Polyline();
polyline1.Stroke = new SolidColorBrush(Colors.Black);
polyline1.StrokeThickness = 4;

var points = new PointCollection();
points.Add(new Windows.Foundation.Point(10, 200));
points.Add(new Windows.Foundation.Point(60, 140));
points.Add(new Windows.Foundation.Point(130, 140));
points.Add(new Windows.Foundation.Point(180, 200));
polyline1.Points = points;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(polyline1);

Voici le rendu de Polyline. Notez que les premiers et les derniers points ne sont pas connectés par le contour de la ligne, car ils se trouvent dans un Polygone.

A rendered Polyline.

Chemin d’accès

Un chemin d'accès est la Forme la plus polyvalente, car vous pouvez l’utiliser pour définir une géométrie arbitraire. Mais avec cette polyvalence vient la complexité. Examinons maintenant comment créer un chemin d’accès de base en XAML.

Vous définissez la géométrie d’un chemin d’accès avec la propriété Data. Il existe deux techniques pour définir des données :

  • Vous pouvez définir une valeur de chaîne pour les données en XAML. Dans ce formulaire, la valeur Path.Data consomme un format de sérialisation pour les graphiques. En règle générale, vous ne modifiez pas cette valeur sous forme de chaîne après son établissement. Au lieu de cela, vous utilisez des outils de conception qui vous permettent de travailler dans une métaphore de conception ou de dessin sur une surface. Ensuite, vous enregistrez ou exportez la sortie, ce qui vous donne un fichier XAML ou un fragment de chaîne XAML avec des informations Path.Data.
  • Vous pouvez définir la propriété Data sur un objet Geometry unique. Cette opération peut être effectuée dans du code ou en XAML. Cette géométrie unique est généralement un GeometryGroup, qui agit comme un conteneur capable de compositer plusieurs définitions de géométrie en un seul objet à des fins du modèle objet. La raison la plus courante est que vous souhaitez utiliser une ou plusieurs courbes et formes complexes qui peuvent être définies en tant que valeurs Segments pour un PathFigure, par exemple BezierSegment.

Cet exemple montre un chemin d’accès qui a pu résulter de l’utilisation de Blend pour Visual Studio pour produire seulement quelques formes vectorielles, puis enregistrer le résultat en XAML. Le chemin total se compose d’un segment de courbe de Bezier et d’un segment de trait. L’exemple est principalement destiné à vous donner quelques exemples des éléments qui existent dans le format de sérialisation Path.Data et ce que représentent les nombres.

Ces données commencent par la commande move, indiquée par « M », qui établit un point de départ absolu pour le chemin d’accès.

Le premier segment est une courbe de Bezier cubique qui commence à (100,200) et se termine à (400,175)l’aide des deux points (100,25) de contrôle et (400,350). Ce segment est indiqué par la commande « C » dans la chaîne d’attribut de données.

Le deuxième segment commence par une commande de ligne horizontale absolue "H", qui spécifie une ligne tracée à partir du point de terminaison (400,175) du sous-chemin précédent jusqu'à un nouveau point de terminaison (280,175). Puisqu’il s’agit d’une commande « lineto » horizontale, la valeur spécifiée est une coordonnéex.

<Path Stroke="DarkGoldenRod" 
      StrokeThickness="3"
      Data="M 100,200 C 100,25 400,350 400,175 H 280" />

Voici le chemin d'accès rendu.

Screenshot of a simple rendered path.

L’exemple suivant montre une utilisation de l’autre technique que nous avons abordée : un GeometryGroup avec un PathGeometry. Cet exemple montre comment utiliser certains des types géométriques qui peuvent être utilisés dans le cadre d’un PathGeometry : PathFigure et les différents éléments qui peuvent être un segment dans PathFigure.Segments.

<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
    <Path.Data>
        <GeometryGroup>
            <RectangleGeometry Rect="50,5 100,10" />
            <RectangleGeometry Rect="5,5 95,180" />
            <EllipseGeometry Center="100, 100" RadiusX="20" RadiusY="30"/>
            <RectangleGeometry Rect="50,175 100,10" />
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure IsClosed="true" StartPoint="50,50">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <BezierSegment Point1="75,300" Point2="125,100" Point3="150,50"/>
                                    <BezierSegment Point1="125,300" Point2="75,100"  Point3="50,50"/>
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </GeometryGroup>
    </Path.Data>
</Path>
var path1 = new Microsoft.UI.Xaml.Shapes.Path();
path1.Fill = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 204, 204, 255));
path1.Stroke = new SolidColorBrush(Colors.Black);
path1.StrokeThickness = 1;

var geometryGroup1 = new GeometryGroup();
var rectangleGeometry1 = new RectangleGeometry();
rectangleGeometry1.Rect = new Rect(50, 5, 100, 10);
var rectangleGeometry2 = new RectangleGeometry();
rectangleGeometry2.Rect = new Rect(5, 5, 95, 180);
geometryGroup1.Children.Add(rectangleGeometry1);
geometryGroup1.Children.Add(rectangleGeometry2);

var ellipseGeometry1 = new EllipseGeometry();
ellipseGeometry1.Center = new Point(100, 100);
ellipseGeometry1.RadiusX = 20;
ellipseGeometry1.RadiusY = 30;
geometryGroup1.Children.Add(ellipseGeometry1);

var pathGeometry1 = new PathGeometry();
var pathFigureCollection1 = new PathFigureCollection();
var pathFigure1 = new PathFigure();
pathFigure1.IsClosed = true;
pathFigure1.StartPoint = new Windows.Foundation.Point(50, 50);
pathFigureCollection1.Add(pathFigure1);
pathGeometry1.Figures = pathFigureCollection1;

var pathSegmentCollection1 = new PathSegmentCollection();
var pathSegment1 = new BezierSegment();
pathSegment1.Point1 = new Point(75, 300);
pathSegment1.Point2 = new Point(125, 100);
pathSegment1.Point3 = new Point(150, 50);
pathSegmentCollection1.Add(pathSegment1);

var pathSegment2 = new BezierSegment();
pathSegment2.Point1 = new Point(125, 300);
pathSegment2.Point2 = new Point(75, 100);
pathSegment2.Point3 = new Point(50, 50);
pathSegmentCollection1.Add(pathSegment2);
pathFigure1.Segments = pathSegmentCollection1;

geometryGroup1.Children.Add(pathGeometry1);
path1.Data = geometryGroup1;

// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot">
layoutRoot.Children.Add(path1);

Voici le chemin d'accès rendu.

Screenshot of a complex rendered path.

L’utilisation de PathGeometry peut être plus lisible que le remplissage d’une chaîne Path.Data. En revanche, Path.Data utilise une syntaxe compatible avec les définitions de chemins d’accès d’image SVG (Scalable Vector Graphics) afin qu’il puisse être utile de porter des graphiques à partir de SVG, ou en tant que sortie d’un outil tel que Blend.