BoxPanel, exemple de panneau personnaliséBoxPanel, an example custom panel

Apprenez à écrire du code pour une classe Panel personnalisée, en implémentant les méthodes ArrangeOverride et MeasureOverride, et en utilisant la propriété Children.Learn to write code for a custom Panel class, implementing ArrangeOverride and MeasureOverride methods, and using the Children property.

API importantes : Panel, ArrangeOverride,MeasureOverrideImportant APIs: Panel, ArrangeOverride,MeasureOverride

L’exemple de code illustre une implémentation de panneau personnalisé, mais nous ne consacrons pas beaucoup de temps à expliquer les concepts de disposition qui influencent la façon dont vous pouvez personnaliser un panneau pour différents scénarios de disposition.The example code shows a custom panel implementation, but we don't devote a lot of time explaining the layout concepts that influence how you can customize a panel for different layout scenarios. Pour plus d’informations sur ces concepts de disposition et sur la manière dont ils peuvent s’appliquer à votre propre scénario de disposition, voir Vue d’ensemble des panneaux personnalisés XAML.If you want more info about these layout concepts and how they might apply to your particular layout scenario, see XAML custom panels overview.

Un panneau est un objet qui fournit un comportement de disposition pour les éléments enfants qu’il contient, lorsque le système de disposition XAML s’exécute et que l’interface utilisateur de votre application est affichée.A panel is an object that provides a layout behavior for child elements it contains, when the XAML layout system runs and your app UI is rendered. Vous pouvez définir des panneaux personnalisés pour la disposition XAML en dérivant une classe personnalisée à partir de la classe Panel.You can define custom panels for XAML layout by deriving a custom class from the Panel class. Vous fournissez le comportement de votre panneau en substituant les méthodes ArrangeOverride et MeasureOverride et en fournissant la logique qui mesure et organise les éléments enfants.You provide behavior for your panel by overriding the ArrangeOverride and MeasureOverride methods, supplying logic that measures and arranges the child elements. Cet exemple dérive de Panel.This example derives from Panel. Lorsque vous commencez à partir de Panel, les méthodes ArrangeOverride et MeasureOverride n’ont pas de comportement de départ.When you start from Panel, ArrangeOverride and MeasureOverride methods don't have a starting behavior. Votre code fournit la passerelle par laquelle les éléments enfants sont portés à la connaissance du système de disposition XAML et sont affichés dans l’interface utilisateur.Your code is providing the gateway by which child elements become known to the XAML layout system and get rendered in the UI. Il est donc très important que votre code prenne en compte tous les éléments enfants et suive les modèles attendus par le système de disposition.So, it's really important that your code accounts for all child elements and follows the patterns the layout system expects.

Votre scénario de dispositionYour layout scenario

Quand vous définissez un panneau personnalisé, vous définissez un scénario de dispositionWhen you define a custom panel, you're defining a layout scenario.

Un scénario de disposition indique :A layout scenario is expressed through:

  • ce que fait le panneau quand il possède des éléments enfants,What the panel will do when it has child elements
  • quand il a des contraintes sur son propre espace,When the panel has constraints on its own space
  • comment la logique du panneau détermine toutes les mesures, placement, positions et dimensionnements qui ont pour résultat la disposition des enfants dans l’interface utilisateur.How the logic of the panel determines all the measurements, placement, positions, and sizings that eventually result in a rendered UI layout of children

L’exemple BoxPanel fourni ici concerne un scénario spécifique.With that in mind, the BoxPanel shown here is for a particular scenario. Pour des raisons de simplification du code, nous n’expliquerons pas le scénario en détail dans cet exemple. Nous nous concentrons plutôt sur les étapes nécessaires et sur les modèles de codage.In the interest of keeping the code foremost in this example, we won't explain the scenario in detail yet, and instead concentrate on the steps needed and the coding patterns. Si vous souhaitez d’abord en savoir plus sur le scénario, passez directement à « Le scénario de BoxPanel » et revenez ensuite au code.If you want to know more about the scenario first, skip ahead to "The scenario for BoxPanel", and then come back to the code.

Commencer par dériver une classe à partir de PanelStart by deriving from Panel

Commencez par dériver une classe personnalisée à partir de Panel.Start by deriving a custom class from Panel. Le moyen le plus simple consiste sans doute à définir un fichier de code distinct pour cette classe, à l’aide des options de menu contextuel Ajouter | Nouvel élément | Classe pour un projet dans l’Explorateur de solutions de Microsoft Visual Studio.Probably the easiest way to do this is to define a separate code file for this class, using the Add | New Item | Class context menu options for a project from the Solution Explorer in Microsoft Visual Studio. Nommez la classe (et le fichier) BoxPanel.Name the class (and file) BoxPanel.

Le fichier modèle d’une classe ne commence pas par beaucoup d’instructions using, car il n’est pas destiné spécifiquement aux applications Windows.The template file for a class doesn't start with many using statements because it's not specifically for Windows apps. Commencez par ajouter des instructions using.So first, add using statements. Le fichier de modèle débute également par quelques instructions using dont vous n’aurez probablement pas besoin et que vous pouvez donc supprimer.The template file also starts with a few using statements that you probably don't need, and can be deleted. Voici une liste d’instructions using qui peuvent résoudre des types dont vous aurez besoin pour du code de panneau personnalisé classique :Here's a suggested list of using statements that can resolve types you'll need for typical custom panel code:

using System;
using System.Collections.Generic; // if you need to cast IEnumerable for iteration, or define your own collection properties
using Windows.Foundation; // Point, Size, and Rect
using Windows.UI.Xaml; // DependencyObject, UIElement, and FrameworkElement
using Windows.UI.Xaml.Controls; // Panel
using Windows.UI.Xaml.Media; // if you need Brushes or other utilities

Maintenant que vous pouvez résoudre Panel, faites-en la classe de base de BoxPanel.Now that you can resolve Panel, make it the base class of BoxPanel. Rendez également BoxPanel public :Also, make BoxPanel public:

public class BoxPanel : Panel
{
}

Au niveau de la classe, définissez certaines valeurs int et double qui seront partagées par plusieurs de vos fonctions logiques, mais qui n’auront pas besoin d’être exposées comme API publiques.At the class level, define some int and double values that will be shared by several of your logic functions, but which won't need to be exposed as public API. Dans l’exemple, elles se nomment : maxrc, rowcount, colcount, cellwidth, cellheight, maxcellheight et aspectratio.In the example, these are named: maxrc, rowcount, colcount, cellwidth, cellheight, maxcellheight, aspectratio.

Après cela, le fichier de code complet ressemble à ceci (les commentaires sur using ont été supprimés, maintenant que vous savez pourquoi ces instructions sont là) :After you've done this, the complete code file looks like this (removing comments on using, now that you know why we have them):

using System;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

public class BoxPanel : Panel 
{
    int maxrc, rowcount, colcount;
    double cellwidth, cellheight, maxcellheight, aspectratio;
}

Dorénavant, nous vous montrerons une définition de membre à la fois, qu’il s’agisse d’une substitution de méthode ou d’un élément de prise en charge tel qu’une propriété de dépendance.From here on out, we'll be showing you one member definition at a time, be that a method override or something supporting such as a dependency property. Vous pouvez ajouter ces éléments au squelette ci-dessus dans n’importe quel ordre. Nous ne remontrerons pas les instructions using ni la définition de la portée de classe dans les extraits avant le code final.You can add these to the skeleton above in any order, and we won't be showing the using statements or the definition of the class scope again in the snippets until we show the final code.

MeasureOverrideMeasureOverride

protected override Size MeasureOverride(Size availableSize)
{
    Size returnSize;
    // Determine the square that can contain this number of items.
    maxrc = (int)Math.Ceiling(Math.Sqrt(Children.Count));
    // Get an aspect ratio from availableSize, decides whether to trim row or column.
    aspectratio = availableSize.Width / availableSize.Height;

    // Now trim this square down to a rect, many times an entire row or column can be omitted.
    if (aspectratio > 1)
    {
        rowcount = maxrc;
        colcount = (maxrc > 2 && Children.Count < maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
    } 
    else 
    {
        rowcount = (maxrc > 2 && Children.Count < maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
        colcount = maxrc;
    }

    // Now that we have a column count, divide available horizontal, that's our cell width.
    cellwidth = (int)Math.Floor(availableSize.Width / colcount);
    // Next get a cell height, same logic of dividing available vertical by rowcount.
    cellheight = Double.IsInfinity(availableSize.Height) ? Double.PositiveInfinity : availableSize.Height / rowcount;
           
    foreach (UIElement child in Children)
    {
        child.Measure(new Size(cellwidth, cellheight));
        maxcellheight = (child.DesiredSize.Height > maxcellheight) ? child.DesiredSize.Height : maxcellheight;
    }
    return LimitUnboundedSize(availableSize);
}

Le modèle nécessaire d’une implémentation MeasureOverride est la boucle qui parcourt chaque élément dans Panel.Children.The necessary pattern of a MeasureOverride implementation is the loop through each element in Panel.Children. Vous devez toujours appeler la méthode Measure sur chacun de ces éléments.Always call the Measure method on each of these elements. Measure possède un paramètre de type Size.Measure has a parameter of type Size. Vous passez ici la taille que votre panneau s’engage à mettre à disposition de cet élément enfant.What you're passing here is the size that your panel is committing to have available for that particular child element. Avant de pouvoir parcourir la boucle et de commencer à appeler Measure, vous devez donc connaître la quantité d’espace que chaque cellule peut allouer.So, before you can do the loop and start calling Measure, you need to know how much space each cell can devote. À partir de la méthode MeasureOverride, vous avez la valeur availableSize.From the MeasureOverride method itself, you have the availableSize value. Il s’agit de la taille qui a été utilisée par le parent du panneau quand il a appelé Measure, ce qui a déclenché initialement l’appel de cette méthode MeasureOverride.That is the size that the panel's parent used when it called Measure, which was the trigger for this MeasureOverride being called in the first place. La logique la plus classique consiste à établir un schéma selon lequel chaque élément enfant divise l’espace de la taille disponible (availableSize) globale du panneau.So a typical logic is to devise a scheme whereby each child element divides the space of the panel's overall availableSize. Vous transmettez ensuite chaque division de taille à la méthode Measure de chaque élément enfant.You then pass each division of size to Measure of each child element.

La manière dont BoxPanel divise la taille est assez simple : il divise son espace en un nombre de cases déterminé en grande partie par le nombre d’éléments.How BoxPanel divides size is fairly simple: it divides its space into a number of boxes that's largely controlled by the number of items. Les tailles des cases sont établies en fonction du nombre de lignes et de colonnes et de la taille globale disponible.Boxes are sized based on row and column count and the available size. Parfois, une ligne ou une colonne d’un carré n’est pas nécessaire. Dans ce cas, elle est supprimée, et le panneau devient un rectangle plutôt qu’un carré en termes de rapport ligne/colonne.Sometimes one row or column from a square isn't needed, so it's dropped and the panel becomes a rectangle rather than square in terms of its row : column ratio. Pour plus d’informations sur cette logique, passez directement à « Le scénario de BoxPanel ».For more info about how this logic was arrived at, skip ahead to "The scenario for BoxPanel".

Que fait donc la passe de mesure ?So what does the measure pass do? Elle définit une valeur pour la propriété DesiredSize en lecture seule sur chaque élément où la méthode Measure a été appelée.It sets a value for the read-only DesiredSize property on each element where Measure was called. Le fait d’avoir une valeur DesiredSize peut être important une fois la passe d’organisation atteinte, car la propriété DesiredSize indique ce que peut ou doit être la taille lors de l’organisation et du rendu final.Having a DesiredSize value is possibly important once you get to the arrange pass, because the DesiredSize communicates what the size can or should be when arranging and in the final rendering. Même si vous n’utilisez pas DesiredSize dans votre propre logique, le système en a besoin.Even if you don't use DesiredSize in your own logic, the system still needs it.

Ce panneau peut être utilisé quand le composant hauteur de availableSize est sans limite.It's possible for this panel to be used when the height component of availableSize is unbounded. Dans ce cas, le panneau n’a aucune hauteur connue à diviser.If that's true, the panel doesn't have a known height to divide. La logique de la passe de mesure signale alors à chaque enfant qu’il n’a pas encore de hauteur limitée.In this case, the logic for the measure pass informs each child that it doesn't have a bounded height, yet. Pour cela, elle transmet un objet Size à l’appel de Measure pour les enfants pour lesquels la propriété Size.Height est infinie.It does so by passing a Size to the Measure call for children where Size.Height is infinite. Cette opération est autorisée.That's legal. Quand la méthode Measure est appelée, la logique veut que DesiredSize prenne la plus petite de ces valeurs : la valeur transmise à Measure ou la taille naturelle de l’élément tirée de facteurs tels que les valeurs Height et Width définies de manière explicite.When Measure is called, the logic is that the DesiredSize is set as the minimum of these: what was passed to Measure, or that element's natural size from factors such as explicitly-set Height and Width.

Notes

La logique interne de StackPanel présente aussi ce comportement : StackPanel passe une valeur de dimension infinie à Measure sur les enfants pour indiquer l’absence de contraintes sur les enfants de la dimension d’orientation.The internal logic of StackPanel also has this behavior: StackPanel passes an infinite dimension value to Measure on children, indicating that there is no constraint on children in the orientation dimension. StackPanel se dimensionne en général de manière dynamique pour pouvoir accueillir tous les enfants d’une pile qui croît dans cette dimension.StackPanel typically sizes itself dynamically, to accommodate all children in a stack that grows in that dimension.

Toutefois, le panneau proprement dit ne peut pas retourner d’objet Size avec une valeur infinie à partir de MeasureOverride ; cela lève une exception durant la disposition.However, the panel itself can't return a Size with an infinite value from MeasureOverride; that throws an exception during layout. Une partie de la logique consiste donc à trouver la hauteur maximale demandée par chaque enfant et à utiliser cette hauteur comme hauteur de cellule dans le cas où elle ne provient pas déjà des propres contraintes de taille du panneau.So, part of the logic is to find out the maximum height that any child requests, and use that height as the cell height in case that isn't coming from the panel's own size constraints already. Voici la fonction d’assistance LimitUnboundedSize référencée dans le code précédent, qui prend ensuite cette hauteur maximale de cellule et l’utilise pour donner au panneau une hauteur finie à retourner et garantit que cellheight est un nombre fini avant d’initier la passe d’organisation :Here's the helper function LimitUnboundedSize that was referenced in previous code, which then takes that maximum cell height and uses it to give the panel a finite height to return, as well as assuring that cellheight is a finite number before the arrange pass is initiated:

// This method is called only if one of the availableSize dimensions of measure is infinite.
// That can happen to height if the panel is close to the root of main app window.
// In this case, base the height of a cell on the max height from desired size
// and base the height of the panel on that number times the #rows.

Size LimitUnboundedSize(Size input)
{
    if (Double.IsInfinity(input.Height))
    {
        input.Height = maxcellheight * colcount;
        cellheight = maxcellheight;
    }
    return input;
}

ArrangeOverrideArrangeOverride

protected override Size ArrangeOverride(Size finalSize)
{
     int count = 1
     double x, y;
     foreach (UIElement child in Children)
     {
          x = (count - 1) % colcount * cellwidth;
          y = ((int)(count - 1) / colcount) * cellheight;
          Point anchorPoint = new Point(x, y);
          child.Arrange(new Rect(anchorPoint, child.DesiredSize));
          count++;
     }
     return finalSize;
}

Le modèle nécessaire d’une implémentation ArrangeOverride est la boucle qui parcourt chaque élément dans Panel.Children.The necessary pattern of an ArrangeOverride implementation is the loop through each element in Panel.Children. Vous devez toujours appeler la méthode Arrange sur chacun de ces éléments.Always call the Arrange method on each of these elements.

Notez qu’il y a moins de calculs que dans MeasureOverride, ce qui est normal.Note how there aren't as many calculations as in MeasureOverride; that's typical. La taille des enfants est déjà connue grâce à la propre logique MeasureOverride du panneau ou grâce à la valeur DesiredSize de chaque enfant définie durant la passe de mesure.The size of children is already known from the panel's own MeasureOverride logic, or from the DesiredSize value of each child set during the measure pass. Toutefois, il reste encore à décider de l’emplacement où apparaîtra chaque enfant dans le panneau.However, we still need to decide the location within the panel where each child will appear. Dans un panneau classique, chaque enfant doit être affiché à une position différente.In a typical panel, each child should render at a different position. Dans les scénarios ordinaires, il n’est pas souhaitable d’avoir un panneau avec des éléments qui se chevauchent (bien qu’il ne soit pas interdit de créer des panneaux avec des chevauchements intentionnels, si votre scénario l’impose.)A panel that creates overlapping elements isn't desirable for typical scenarios (although it's not out of the question to create panels that have purposeful overlaps, if that's really your intended scenario).

Ce panneau organise les éléments selon un concept de lignes et de colonnes.This panel arranges by the concept of rows and columns. Le nombre de lignes et de colonnes a déjà été calculé (il était nécessaire pour la mesure).The number of rows and columns was already calculated (it was necessary for measurement). La forme des lignes et des colonnes et la taille connue de chaque cellule contribuent maintenant à la logique de définition d’une position de rendu (l’objet anchorPoint) pour chaque élément contenu dans ce panneau.So now the shape of the rows and columns plus the known sizes of each cell contribute to the logic of defining a rendering position (the anchorPoint) for each element that this panel contains. Ce Point et la valeur Size déjà obtenue suite à la mesure sont utilisés comme composants pour la construction d’un objet Rect.That Point, along with the Size already known from measure, are used as the two components that construct a Rect. Rect est le type d’entrée pour Arrange.Rect is the input type for Arrange.

Les panneaux doivent parfois tronquer leur contenu.Panels sometimes need to clip their content. Dans ce cas, la taille coupée est celle présente dans DesiredSize, car la logique de Measure la définit comme le minimum de ce qui a été transmis à Measure, ou d’autres facteurs de taille naturelle.If they do, the clipped size is the size that's present in DesiredSize, because the Measure logic sets it as the minimum of what was passed to Measure, or other natural size factors. Ainsi, il n’est généralement pas nécessaire de se préoccuper de la troncature durant Arrange. Celle-ci aura simplement lieu en fonction de la transmission de la valeur DesiredSize lors de chaque appel à Arrange.So you don't typically need to specifically check for clipping during Arrange; the clipping just happens based on passing the DesiredSize through to each Arrange call.

Un décompte n’est pas toujours nécessaire durant le bouclage si toutes les informations dont vous avez besoin pour définir la position de rendu sont déjà connues par un autre moyen.You don't always need a count while going through the loop if all the info you need for defining the rendering position is known by other means. Par exemple, dans la logique de disposition Canvas, la position dans la collection Children n’a pas d’importance.For example, in Canvas layout logic, the position in the Children collection doesn't matter. Toutes les informations nécessaires pour positionner chaque élément dans un objet Canvas sont connues par la lecture des valeurs Canvas.Left et Canvas.Top des enfants dans le cadre de la logique d’organisation.All the info needed to position each element in a Canvas is known by reading Canvas.Left and Canvas.Top values of children as part of the arrange logic. La logique BoxPanel a besoin d’un décompte à des fins de comparaison avec colcount, afin de savoir quand commencer une nouvelle ligne et décaler la valeur y.The BoxPanel logic happens to need a count to compare to the colcount so it's known when to begin a new row and offset the y value.

Il est courant que la valeur finalSize d’entrée et la valeur Size retournée à partir d’une implémentation ArrangeOverride soient identiques.It's typical that the input finalSize and the Size you return from a ArrangeOverride implementation are the same. Pour plus d’informations à ce sujet, voir « ArrangeOverride » dans Vue d’ensemble des panneaux personnalisés XAML.For more info about why, see "ArrangeOverride" section of XAML custom panels overview.

Un affinement : le contrôle du nombre de lignes et de colonnesA refinement: controlling the row vs. column count

Vous pourriez compiler et utiliser ce panneau tel quel.You could compile and use this panel just as it is now. Nous allons toutefois ajouter un petit affinement.However, we'll add one more refinement. Dans le code fourni, la logique place la ligne ou colonne supplémentaire du côté où la proportion est la plus longue.In the code just shown, the logic puts the extra row or column on the side that's longest in aspect ratio. Pour un meilleur contrôle des formes des cellules, il peut être souhaitable de choisir un ensemble de cellules 4x3 plutôt que 3x4, même si les proportions du panneau sont définies sur « Portrait ».But for greater control over the shapes of cells, it might be desirable to choose a 4x3 set of cells instead of 3x4 even if the panel's own aspect ratio is "portrait." Nous allons donc ajouter une propriété de dépendance facultative que le consommateur du panneau peut définir pour contrôler le comportement.So we'll add an optional dependency property that the panel consumer can set to control that behavior. Voici la définition de cette propriété de dépendance. Elle est très simple :Here's the dependency property definition, which is very basic:

public static readonly DependencyProperty UseOppositeRCRatioProperty =
   DependencyProperty.Register("UseOppositeRCRatio", typeof(bool), typeof(BoxPanel), null);

public bool UseSquareCells
{
    get { return (bool)GetValue(UseOppositeRCRatioProperty); }
    set { SetValue(UseOppositeRCRatioProperty, value); }
}

Et voici comment l’utilisation de UseOppositeRCRatio affecte la logique de mesure.And here's how using UseOppositeRCRatio impacts the measure logic. Tout ce qu’elle fait, c’est modifier la façon dont rowcount et colcount sont dérivées de maxrc et des proportions réelles, ce qui provoque des différences de taille correspondantes pour chaque cellule.Really all it's doing is changing how rowcount and colcount are derived from maxrc and the true aspect ratio, and there are corresponding size differences for each cell because of that. Quand UseOppositeRCRatio est true, la valeur des proportions réelles est inversée avant d’être utilisée pour définir le nombre de lignes et de colonnes.When UseOppositeRCRatio is true, it inverts the value of the true aspect ratio before using it for row and column counts.

if (UseOppositeRCRatio) { aspectratio = 1 / aspectratio;}

Le scénario de BoxPanelThe scenario for BoxPanel

BoxPanel est un panneau pour lequel le principal facteur qui permet de déterminer le mode de répartition de l’espace est la connaissance du nombre d’éléments enfants et la division de l’espace disponible connu pour le panneau.The particular scenario for BoxPanel is that it's a panel where one of the main determinants of how to divide space is by knowing the number of child items, and dividing the known available space for the panel. Les panneaux sont, à la base, des formes rectangulaires.Panels are innately rectangle shapes. De nombreux panneaux opèrent en divisant cet espace rectangulaire en plusieurs rectangles. C’est ce que fait Grid pour ses cellules.Many panels operate by dividing that rectangle space into further rectangles; that's what Grid does for its cells. Dans le cas de Grid, la taille des cellules est définie par les valeurs ColumnDefinition et RowDefinition et les éléments déclarent la cellule exacte dans laquelle ils vont avec les propriétés jointes Grid.Row et Grid.Column.In Grid's case, the size of the cells is set by ColumnDefinition and RowDefinition values, and elements declare the exact cell they go into with Grid.Row and Grid.Column attached properties. Pour obtenir une bonne disposition à partir d’une Grid, il faut généralement connaître au préalable le nombre d’éléments enfants, pour qu’il y ait suffisamment de cellules et que chaque élément enfant définisse ses propriétés jointes en fonction de la taille de sa propre cellule.Getting good layout from a Grid usually requires knowing the number of child elements beforehand, so that there are enough cells and each child element sets its attached properties to fit into its own cell.

Et si le nombre d’enfants est dynamique ?But what if the number of children is dynamic? C’est parfaitement possible ; votre code d’application peut ajouter des éléments aux collections en réponse à toute condition d’exécution dynamique que vous jugez assez importante pour devoir mettre à jour votre interface utilisateur.That's certainly possible; your app code can add items to collections, in response to any dynamic run-time condition you consider to be important enough to be worth updating your UI. Si vous utilisez la liaison de données vers des collections ou des objets métier, l’obtention de ces mises à jour et la mise à jour de l’interface utilisateur sont gérées automatiquement. Il s’agit donc de la technique de prédilection (voir Présentation détaillée de la liaison de données).If you're using data binding to backing collections/business objects, getting such updates and updating the UI is handled automatically, so that's often the preferred technique (see Data binding in depth).

Mais les scénarios d’application ne se prêtent pas tous à la liaison de données.But not all app scenarios lend themselves to data binding. Parfois, vous devez créer de nouveaux éléments d’interface utilisateur au moment de l’exécution et les rendre visibles.Sometimes, you need to create new UI elements at runtime and make them visible. BoxPanel convient dans ce scénario.BoxPanel is for this scenario. Une modification du nombre d’éléments enfants ne constitue pas un problème pour BoxPanel, car il utilise le nombre d’enfants dans les calculs et ajuste à la fois les éléments enfants nouveaux et existants pour qu’ils soient tous contenus dans la nouvelle disposition.A changing number of child items is no problem for BoxPanel because it's using the child count in calculations, and adjusts both the existing and new child elements into a new layout so they all fit.

Un scénario avancé pour étendre BoxPanel (non illustré ici) consisterait à la fois à gérer les enfants dynamiques et à utiliser la valeur DesiredSize d’un enfant comme facteur prioritaire pour le dimensionnement des cellules individuelles.An advanced scenario for extending BoxPanel further (not shown here) could both accommodate dynamic children and use a child's DesiredSize as a stronger factor for the sizing of individual cells. Ce scénario pourrait utiliser des tailles de lignes et de colonnes variables ou des formes autres que des grilles afin de réduire l’espace « perdu ».This scenario might use varying row or column sizes or non-grid shapes so that there's less "wasted" space. Cela requiert une stratégie afin de déterminer comment plusieurs rectangles de différentes tailles et proportions peuvent rentrer dans un rectangle contenant du point de vue esthétique et en cas de très petite taille.This requires a strategy for how multiple rectangles of various sizes and aspect ratios can all fit into a containing rectangle both for aesthetics and smallest size. BoxPanel n’offre pas cette fonctionnalité. Il utilise une technique plus simple pour diviser l’espace.BoxPanel doesn't do that; it's using a simpler technique for dividing space. La technique employée par BoxPanel consiste à déterminer le plus petit nombre de carré supérieur au nombre d’enfants.BoxPanel's technique is to determine the least square number that's greater than the child count. Par exemple, 9 éléments pourraient être contenus dans un carré de 3x3.For example, 9 items would fit in a 3x3 square. 10 éléments nécessitent un carré de 4x4.10 items require a 4x4 square. Toutefois, vous pouvez souvent ajuster les éléments tout en supprimant une ligne ou une colonne dans le carré de départ, pour gagner de l’espace.However, you can often fit items while still removing one row or column of the starting square, to save space. Avec 10 éléments, par exemple, vous pourriez utiliser un rectangle de 4x3 ou de 3x4.In the count=10 example, that fits in a 4x3 or 3x4 rectangle.

Vous vous demandez peut-être pourquoi le panneau ne choisirait pas plutôt un rectangle de 5x2 pour 10 éléments.You might wonder why the panel wouldn't instead choose 5x2 for 10 items, because that fits the item number neatly. En pratique, les panneaux sont dimensionnés sous la forme de rectangles qui ont rarement des proportions fortement orientées.However, in practice, panels are sized as rectangles that seldom have a strongly oriented aspect ratio. La technique des moindres carrés permet à la logique de dimensionnement de bien fonctionner avec les formes de disposition classiques tout en évitant les dimensionnements où des proportions irrégulières sont appliquées aux cellules.The least-squares technique is a way to bias the sizing logic to work well with typical layout shapes and not encourage sizing where the cell shapes get odd aspect ratios.

Informations de référenceReference

ConceptsConcepts