BoxPanel, ein Beispiel für benutzerdefinierte PanelsBoxPanel, an example custom panel

Hier erfahren Sie, wie Sie Code für eine benutzerdefinierte Panel-Klasse schreiben. Dabei implementieren Sie die Methoden ArrangeOverride und MeasureOverride und verwenden die Children-Eigenschaft.Learn to write code for a custom Panel class, implementing ArrangeOverride and MeasureOverride methods, and using the Children property.

Wichtige APIs: Panel, ArrangeOverride,MeasureOverrideImportant APIs: Panel, ArrangeOverride,MeasureOverride

Der Beispielcode zeigt eine benutzerdefinierte Panelimplementierung. Wir gehen jedoch nicht detailliert auf die Erklärung der Layoutkonzepte ein, die Einfluss darauf haben, wie Sie ein Panel für verschiedene Layoutszenarien anpassen können.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. Wenn Sie weitere Informationen zu diesen Layoutkonzepten und der Anwendbarkeit auf Ihr jeweiliges Layoutszenario benötigen, lesen Sie Übersicht über benutzerdefinierte XAML-Panels.If you want more info about these layout concepts and how they might apply to your particular layout scenario, see XAML custom panels overview.

Ein Panel ist ein Objekt, das ein Layoutverhalten für die darin enthaltenen untergeordneten Elemente bereitstellt, wenn das XAML-Layoutsystem ausgeführt und die Benutzeroberfläche Ihrer App dargestellt wird.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. Sie können für ein XAML-Layout benutzerdefinierte Panels definieren, indem Sie eine benutzerdefinierte Klasse aus der Panel-Klasse ableiten.You can define custom panels for XAML layout by deriving a custom class from the Panel class. Das Verhalten für das Panel wird bereitgestellt, indem Sie die Methoden ArrangeOverride und MeasureOverride außer Kraft setzen und somit eine Logik liefern, die die untergeordneten Elemente misst und anordnet.You provide behavior for your panel by overriding the ArrangeOverride and MeasureOverride methods, supplying logic that measures and arranges the child elements. Dieses Beispiel wurde von Panel abgeleitet.This example derives from Panel. Wenn Sie mit einem Panel beginnen, haben die Methoden ArrangeOverride und MeasureOverride kein Startverhalten.When you start from Panel, ArrangeOverride and MeasureOverride methods don't have a starting behavior. Ihr Code stellt das Gateway bereit, mit dessen Hilfe die untergeordneten Elemente dem XAML-Layoutsystem mitgeteilt und auf der Benutzeroberfläche gerendert werden.Your code is providing the gateway by which child elements become known to the XAML layout system and get rendered in the UI. Daher ist es wirklich wichtig, dass der Code alle untergeordneten Elemente berücksichtigt und dem vom Layoutsystem erwarteten Muster folgt.So, it's really important that your code accounts for all child elements and follows the patterns the layout system expects.

Ihr LayoutszenarioYour layout scenario

Beim Definieren eines benutzerdefinierten Panels definieren Sie ein Layoutszenario.When you define a custom panel, you're defining a layout scenario.

Ein Layoutszenario wird durch folgende Aspekte ausgedrückt:A layout scenario is expressed through:

  • Was geschieht, wenn das Panel untergeordnete Elemente enthält?What the panel will do when it has child elements
  • Gelten für den eigenen Bereich des Panels Einschränkungen?When the panel has constraints on its own space
  • Wie bestimmt die Logik des Panels alle Messwerte, Platzierungspositionen und Größenanpassungen, die letztlich zu einem gerenderten UI-Layout der untergeordneten Elemente führen?How the logic of the panel determines all the measurements, placement, positions, and sizings that eventually result in a rendered UI layout of children

Unter Berücksichtigung dieser Aspekte ist das hier gezeigte BoxPanel für ein bestimmtes Szenario geeignet.With that in mind, the BoxPanel shown here is for a particular scenario. Da in diesem Beispiel der Code im Vordergrund stehen soll, werden wir das Szenario noch nicht detailliert erläutern, sondern uns stattdessen auf die notwendigen Schritte und die Codierungsmuster konzentrieren.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. Wenn Sie sich zunächst detaillierter über das Szenario informieren möchten, lesen Sie unter Szenario für BoxPanel weiter, und kehren Sie später zum Code zurück.If you want to know more about the scenario first, skip ahead to "The scenario for BoxPanel", and then come back to the code.

Erster Schritt: Ableiten von der Panel-KlasseStart by deriving from Panel

Leiten Sie zunächst aus der Panel-Klasse eine benutzerdefinierte Klasse ab.Start by deriving a custom class from Panel. Die einfachste Methode dafür ist wahrscheinlich, mithilfe der Kontextmenüoptionen Hinzufügen | Neues Element | Klasse für ein Projekt aus dem 5Projektmappen-Explorer in Microsoft Visual Studio eine separate Codedatei für diese Klasse zu definieren.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. Benennen Sie die Klasse (und Datei) mit BoxPanel.Name the class (and file) BoxPanel.

Die Vorlagendatei für eine Klasse beginnt nicht mit vielen using-Anweisungen, weil sie nicht ausschließlich für Windows-Apps bestimmt ist.The template file for a class doesn't start with many using statements because it's not specifically for Windows apps. Fügen Sie daher zuerst using-Anweisungen hinzu.So first, add using statements. Die Vorlagendatei beginnt außerdem mit einigen using-Anweisungen, die Sie vielleicht nicht benötigen, und die gelöscht werden können.The template file also starts with a few using statements that you probably don't need, and can be deleted. Hier ist eine Liste mit Vorschlägen für using-Anweisungen zur Auflösung von Typen, die Sie für einen typischen Code eines benutzerdefinierten Panels benötigen: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

Da Sie nun die Panel-Klasse auflösen können, legen Sie diese als Basisklasse für BoxPanel fest.Now that you can resolve Panel, make it the base class of BoxPanel. Machen Sie BoxPanel zudem öffentlich:Also, make BoxPanel public:

public class BoxPanel : Panel
{
}

Definieren Sie auf Klassenebene einige int- und double-Werte, die von mehreren Logikfunktionen gemeinsam verwendet werden, aber nicht als öffentliche API verfügbar gemacht werden müssen.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. In dem Beispiel sind diese wie folgt benannt: maxrc, rowcount, colcount, cellwidth, cellheight, maxcellheight, aspectratio.In the example, these are named: maxrc, rowcount, colcount, cellwidth, cellheight, maxcellheight, aspectratio.

Nachdem Sie dies getan haben, sieht die vollständige Codedatei wie folgt aus (Kommentare zu using werden entfernt, da Sie nun wissen, wozu sie dienen):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;
}

Ab hier zeigen wir Ihnen jeweils eine Memberdefinition. Dabei kann es sich um eine Methodenüberschreibung oder eine Unterstützung wie eine Abhängigkeitseigenschaft handeln.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. Sie können diese dem oben gezeigten Skelett in beliebiger Reihenfolge hinzufügen. Wir zeigen die using-Anweisungen oder die Definition des Klassenbereichs erst wieder in den Codeausschnitten, wenn wir den finalen Code präsentieren.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);
}

Das notwendige Muster einer MeasureOverride-Implementierung ist die Schleife durch die einzelnen Elemente in Panel.Children.The necessary pattern of a MeasureOverride implementation is the loop through each element in Panel.Children. Rufen Sie für jedes dieser Elemente immer die Measure-Methode auf.Always call the Measure method on each of these elements. Measure hat einen Parameter vom Typ Size.Measure has a parameter of type Size. An dieser Stelle übergeben Sie die Größe, die dem Panel für das jeweilige untergeordnete Element zur Verfügung stehen soll.What you're passing here is the size that your panel is committing to have available for that particular child element. Bevor Sie also den Schleife ausführen und mit dem Measure-Aufruf beginnen können, müssen Sie wissen, wie viel Platz die einzelnen Zellen belegen können.So, before you can do the loop and start calling Measure, you need to know how much space each cell can devote. Aus der MeasureOverride-Methode selbst stammt der availableSize-Wert.From the MeasureOverride method itself, you have the availableSize value. Dies ist die Größe, die vom übergeordneten Panel beim Measure-Aufruf verwendet wurde. Dies war in erster Linie der Auslöser für diesen MeasureOverride-Aufruf.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. Eine typische Logik besteht also darin, ein Schema zu entwerfen, in dem jedes untergeordnete Element den Raum des gesamten availableSize-Werts für das Panel teilt.So a typical logic is to devise a scheme whereby each child element divides the space of the panel's overall availableSize. Anschließend übergeben Sie die einzelnen Größenteilungen für jedes untergeordnete Element an Measure.You then pass each division of size to Measure of each child element.

Die Größe wird vom BoxPanel ziemlich einfach aufgeteilt: Es teilt den Platz in mehrere Felder, deren Anzahl größtenteils durch die Anzahl Elemente bestimmt wird.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. Die Größenanpassung der Felder basiert auf der Anzahl der Zeilen und Spalten und auf der verfügbaren Größe.Boxes are sized based on row and column count and the available size. Mitunter wird eine Zeile oder Spalte eines Quadrats nicht benötigt. Demzufolge wird es verworfen, und der Bereich ist bezüglich des Zeilen-/Spaltenverhältnisses kein Quadrat mehr, sondern wird zu einem Rechteck.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. Wenn Sie weitere Informationen dazu erhalten möchten, wie diese Logik erstellt wurde, lesen Sie unter „Das Szenario für BoxPanel“ weiter.For more info about how this logic was arrived at, skip ahead to "The scenario for BoxPanel".

Was geschieht also während des Messdurchlaufs?So what does the measure pass do? Dabei wird für jedes Element, bei dem Measure aufgerufen wurde, ein Wert für die schreibgeschützte DesiredSize-Eigenschaft festgelegt.It sets a value for the read-only DesiredSize property on each element where Measure was called. Das Vorhandensein eines DesiredSize-Werts kann beim Erreichen des Anordnungsdurchlaufs von Bedeutung sein, weil DesiredSize Aufschluss darüber gibt, wie die Größe bei der Anordnung und in der finalen Darstellung lauten kann oder soll.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. Selbst wenn Sie DesiredSize in Ihrer eigenen Logik nicht verwenden, wird der Wert dennoch vom System benötigt.Even if you don't use DesiredSize in your own logic, the system still needs it.

Dieses Panel kann verwendet werden, wenn die Höhenkomponenten von availableSize unbegrenzt ist.It's possible for this panel to be used when the height component of availableSize is unbounded. Wenn dies wahr ist, verfügt das Panel über keine bekannte Höhe zum Teilen.If that's true, the panel doesn't have a known height to divide. In diesem Fall informiert die Logik für den Messdurchlauf jedes untergeordnete Element darüber, dass es noch keine begrenzte Höhe aufweist.In this case, the logic for the measure pass informs each child that it doesn't have a bounded height, yet. Dazu wird ein Size-Wert an den Measure-Aufruf für untergeordnete Elemente übergeben, wobei Size.Height endlos ist.It does so by passing a Size to the Measure call for children where Size.Height is infinite. Dies ist zulässig.That's legal. Beim Aufruf von Measure wird der DesiredSize-Wert laut Logik als Minimalwert von Folgendem festgelegt: an Measure übergebene Werte oder die natürliche Größe des jeweiligen Elements aus Faktoren wie den explizit festgelegten Werten Height und Width.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.

Hinweis

Die interne Logik von StackPanel hat auch dieses Verhalten: StackPanel übergibt einen endlosen Dimensionswert an Measure für untergeordnete Elemente. Hiermit wird angegeben, dass für untergeordnete Elemente in der Ausrichtungsdimension keine Beschränkung vorliegt.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 passt seine Größe normalerweise dynamisch an, sodass alle untergeordneten Elemente in einem Stapel Platz haben, der in dieser Dimension zunimmt.StackPanel typically sizes itself dynamically, to accommodate all children in a stack that grows in that dimension.

Das Panel selbst kann aber kein Size-Element mit einem endlosen Wert aus MeasureOverride zurückgeben, weil dadurch im Layout eine Ausnahme ausgelöst wird.However, the panel itself can't return a Size with an infinite value from MeasureOverride; that throws an exception during layout. Teil dieser Logik ist es also, die von einem beliebigen untergeordneten Element angeforderte Maximalhöhe herauszufinden und diese Höhe als Zellenhöhe zu verwenden, wenn sie nicht bereits aus den eigenen Größenbeschränkungen des Panels stammt.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. Dies ist die Hilfsfunktion LimitUnboundedSize, auf die im vorherigen Code verwiesen wurde, der diese Zellenmaximalhöhe verwendet, um dem Panel eine begrenzte Höhe zuzuweisen. Zudem wird davon ausgegangen, dass cellheight eine finite Zahl ist, bevor der Anordnungsdurchlauf initiiert wird: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;
}

Das notwendige Muster einer ArrangeOverride-Implementierung ist die Schleife durch die einzelnen Elemente in Panel.Children.The necessary pattern of an ArrangeOverride implementation is the loop through each element in Panel.Children. Rufen Sie für jedes dieser Elemente immer die Arrange-Methode auf.Always call the Arrange method on each of these elements.

Beachten Sie, dass hier nicht so viele Berechnungen erfolgen wie in MeasureOverride – das ist typisch.Note how there aren't as many calculations as in MeasureOverride; that's typical. Die Größe der untergeordneten Elemente ist bereits aus der eigenen MeasureOverride-Logik des Panels oder aus dem DesiredSize-Wert der einzelnen untergeordneten Elemente bekannt, der während des Messdurchlaufs festgelegt wird.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. Dennoch müssen wir die Position innerhalb des Panels festlegen, an der die einzelnen untergeordneten Elemente angezeigt werden.However, we still need to decide the location within the panel where each child will appear. In einem typischen Panel sollte jedes untergeordnete Element an einer anderen Position gerendert werden.In a typical panel, each child should render at a different position. Ein Panel, das überlappende Elemente erzeugt, ist für gewöhnliche Szenarien nicht wünschenswert (obwohl Sie durchaus Panels mit zweckmäßigen Überlappungen erstellen können, wenn dies wirklich das beabsichtigte Szenario ist).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).

Dieses Panel wird nach dem Konzept von Zeilen und Spalten angeordnet.This panel arranges by the concept of rows and columns. Die Anzahl Zeilen und Spalten wurde bereits berechnet (dies war für die Messung nötig).The number of rows and columns was already calculated (it was necessary for measurement). Die Form der Zeilen und Spalten sowie die bekannten Größen der einzelnen Zellen sind also Teil der Definitionslogik einer Darstellungsposition (anchorPoint) für jedes Element, das in diesem Panel enthalten ist.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. Dieser Point-Wert und der bereits aus der Messung bekannte Size-Wert werden zusammen als die beiden Komponenten verwendet, aus denen eine Rect-Struktur konstruiert wird.That Point, along with the Size already known from measure, are used as the two components that construct a Rect. Rect ist der Eingabetyp für Arrange.Rect is the input type for Arrange.

Panels müssen die zugehörigen Inhalte mitunter beschneiden.Panels sometimes need to clip their content. Wenn dies der Fall ist, entspricht die beschnittene Größe der in DesiredSize vorhandenen Größe, weil sie die Measure-Logik als Mindestwert, der an Measure übergeben wurde, oder als andere natürliche Größenfaktoren festlegt.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. Normalerweise müssen Sie die Beschneidung in der Arrange-Phase also nicht überprüfen. Die Beschneidung erfolgt einfach basierend auf der Übergabe der DesiredSize an die einzelnen Arrange-Aufrufe.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.

Beim Durchlaufen der Schleife benötigen Sie nicht immer eine Zählung, wenn alle zum Definieren der Renderingposition benötigten Informationen anderweitig bekannt sind.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. Zum Beispiel ist in der Canvas-Layoutlogik die Position in der Children-Sammlung unerheblich.For example, in Canvas layout logic, the position in the Children collection doesn't matter. Alle zum Positionieren der einzelnen Elemente in einer Canvas benötigten Infos sind durch Lesen der Werte Canvas.Left und Canvas.Top der untergeordneten Elemente im Rahmen der Anordnungslogik bekannt.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. Die BoxPanel-Logik benötigt eine Zählung für den Vergleich mit dem colcount-Wert, damit ersichtlich ist, wann eine neue Zeile begonnen und der y-Wert versetzt wird.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.

Normalerweise sind der eingegebene Wert für finalSize und der Wert für Size, der aus einer ArrangeOverride-Implementierung zurückgegeben wird, identisch.It's typical that the input finalSize and the Size you return from a ArrangeOverride implementation are the same. Weitere Informationen zu den entsprechenden Gründen finden Sie unter Übersicht über benutzerdefinierte XAML-Panels im Abschnitt ArrangeOverride.For more info about why, see "ArrangeOverride" section of XAML custom panels overview.

Verfeinerung: Steuern der Anzahl der Zeilen und SpaltenA refinement: controlling the row vs. column count

Sie könnten diesen Bereich nun in diesem Zustand kompilieren und verwenden.You could compile and use this panel just as it is now. Wir fügen jedoch noch eine Verfeinerung hinzu.However, we'll add one more refinement. In dem gerade gezeigten Code positioniert die Logik die Extrazeile oder -spalte auf der Seite, die im Seitenverhältnis die längste ist.In the code just shown, the logic puts the extra row or column on the side that's longest in aspect ratio. Aus Gründen der besseren Kontrolle über die Formen der Zellen kann es jedoch wünschenswert sein, eine 4-x-3-Zellenmenge anstatt 3 x 4 auszuwählen. Dies ist auch dann der Fall, wenn das eigene Seitenverhältnis des Panels „Hochformat“ lautet.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." Daher fügen wir eine optionale Abhängigkeitseigenschaft hinzu, die der Benutzer des Panels zum Steuern dieses Verhaltens festlegen kann.So we'll add an optional dependency property that the panel consumer can set to control that behavior. Hier finden Sie die sehr einfache Definition der Abhängigkeitseigenschaft: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); }
}

Und so wirkt sich die Verwendung von UseOppositeRCRatio auf die Messlogik aus.And here's how using UseOppositeRCRatio impacts the measure logic. Dabei werden tatsächlich lediglich die Ableitungen von rowcount und colcount von maxrc und das tatsächliche Seitenverhältnis geändert. Daraus ergeben sich für jede Zelle entsprechende Größenunterschiede.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. Wenn UseOppositeRCRatiotrue ist, wird der Wert des tatsächlichen Seitenverhältnisses vor dessen Verwendung für die Zählung der Zeilen und Spalten invertiert.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;}

Szenario für BoxPanelThe scenario for BoxPanel

Das besondere Szenario für BoxPanel sieht so aus, dass es sich um einen Bereich handelt, in dem sich eine der Hauptdeterminante zur Aufteilung der Fläche aus der Kenntnis der Anzahl untergeordneter Elemente ergibt und in dem die bekannte verfügbare Fläche für den Bereich geteilt wird.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. Bereiche sind immanente Rechtecksformen.Panels are innately rectangle shapes. Viele Panels funktionieren so, dass die rechteckige Fläche in weitere Rechtecke geteilt wird. Genau diese Funktion übernimmt die Grid-Klasse für die zugehörigen Zellen.Many panels operate by dividing that rectangle space into further rectangles; that's what Grid does for its cells. Im Fall von Grid wird die Größe der Zellen durch ColumnDefinition- und RowDefinition-Werte festgelegt, und Elemente deklarieren die exakte Zelle, in die sie über die angehängten Eigenschaften Grid.Row und Grid.Column einfließen.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. Zum Abrufen eines guten Layouts aus einem Grid muss zuvor normalerweise die Anzahl der untergeordneten Elemente bekannt sein, sodass genügend Zellen vorhanden sind und jedes untergeordnete Element seine angehängten Eigenschaften so festlegt, dass es in seine eigene Zelle passt.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.

Wie verhält es sich jedoch, wenn die Anzahl untergeordneter Elemente dynamisch ist?But what if the number of children is dynamic? Das ist durchaus möglich. Der Code Ihrer App kann Sammlungen Elemente hinzufügen. Dies geschieht in Reaktion auf dynamische Laufzeitzustände, die Sie für wichtig genug erachten, um die Benutzeroberfläche zu aktualisieren.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. Wenn Sie eine Datenbindung zum Sichern von Sammlungen/Geschäftsobjekten verwenden, erfolgen der Abruf solcher Updates und die Aktualisierung der Benutzeroberfläche automatisch. Daher ist dies oftmals die bevorzugte Technik (siehe Datenbindung im Detail).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).

Aber nicht alle App-Szenarien eignen sich für die Datenbindung.But not all app scenarios lend themselves to data binding. Manchmal müssen Sie zur Laufzeit neue UI-Elemente erstellen und sichtbar machen.Sometimes, you need to create new UI elements at runtime and make them visible. BoxPanel ist für dieses Szenario gedacht.BoxPanel is for this scenario. Eine Änderung der Anzahl der untergeordneten Elemente ist kein Problem für BoxPanel, weil diese Anzahl in Berechnungen verwendet wird und sowohl die vorhandenen als auch die neuen untergeordneten Elemente in einem neuen Layout angepasst werden, sodass sie alle passen.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.

Ein erweitertes Szenario für das Erweitern von BoxPanel (hier nicht gezeigt) könnte sowohl dynamische untergeordnete Elemente umfassen als auch den DesiredSize-Wert eines untergeordneten Elements als stärkeren Faktor für die Größenanpassung einzelner Zellen verwenden.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. In diesem Szenario könnten auch die Zeilen- oder Spaltengrößen oder Nichtrasterformen variieren, sodass weniger Platz „verschwendet“ wird.This scenario might use varying row or column sizes or non-grid shapes so that there's less "wasted" space. Dies erfordert eine Strategie für die Einpassung von mehreren Rechtecken mit verschiedenen Größen und Seitenverhältnissen in ein einschließendes Rechteck, um ästhetische Aspekte ebenso wie die kleinste Größe zu berücksichtigen.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 verwendet solch eine Strategie nicht. Stattdessen wird der Platz mithilfe einer einfacheren Technik aufgeteilt.BoxPanel doesn't do that; it's using a simpler technique for dividing space. Die BoxPanel-Technik besteht darin, die kleinste Quadratzahl zu bestimmen, die größer als die Anzahl der untergeordneten Elemente ist.BoxPanel's technique is to determine the least square number that's greater than the child count. Beispielsweise würden neun Elemente in ein Quadrat mit den Abmessungen 3 × 3 passen.For example, 9 items would fit in a 3x3 square. Für zehn Elemente wird ein Quadrat mit den Abmessungen 4 × 4 benötigt.10 items require a 4x4 square. Oftmals können Sie aber Elemente zuordnen und trotzdem eine Zeile oder Spalte aus dem Ausgangsquadrat entfernen, um Platz zu sparen.However, you can often fit items while still removing one row or column of the starting square, to save space. Im Beispiel mit der Anzahl 10 würde das in ein Rechteck mit 4 x 3 oder 3 x 4 passen.In the count=10 example, that fits in a 4x3 or 3x4 rectangle.

Möglicherweise fragen Sie sich, warum das Panel nicht stattdessen die Abmessung 5 x 2 für zehn Elemente auswählt, da die Elementanzahl dann genau passen würde.You might wonder why the panel wouldn't instead choose 5x2 for 10 items, because that fits the item number neatly. In der Praxis wird die Größe von Panels aber als Rechteck festgelegt, das nur selten ein fest ausgerichtetes Seitenverhältnis aufweist.However, in practice, panels are sized as rectangles that seldom have a strongly oriented aspect ratio. Die Technik mit den kleinsten Quadraten ist eine Methode, um die Größenfestlegungslogik so zu beeinflussen, dass sie ordnungsgemäß mit den typischen Layoutformen funktioniert und um zu verhindern, dass durch die Größenfestlegung eigenartige Seitenverhältnisse der Zellenformen auftreten.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.

ReferenzReference

KonzepteConcepts