Übersicht über benutzerdefinierte XAML-Panels

Ein Panel ist ein Objekt, das ein Layoutverhalten für die in diesem enthaltenen untergeordneten Elemente bereitstellt, wenn das Extensible Application Markup Language (XAML)-Layoutsystem ausgeführt und die Benutzeroberfläche Ihrer App dargestellt wird.

Wichtige APIs:Panel, ArrangeOverride, MeasureOverride

Sie können für ein XAML-Layout benutzerdefinierte Panels definieren, indem Sie eine benutzerdefinierte Klasse aus der Panel-Klasse ableiten. Das Verhalten für das Panel stellen Sie bereit, indem Sie die Methoden MeasureOverride und ArrangeOverride überschreiben und somit eine Logik liefern, die die untergeordneten Elemente misst und anordnet.

Die Panel-Basisklasse

Um eine benutzerdefinierte Panelklasse zu definieren, können Sie entweder eine direkte Ableitung von der Panel-Klasse durchführen oder eine Ableitung von einer der praktischen Panelklassen durchführen, die nicht versiegelt sind, beispielsweise Grid oder StackPanel. Es ist einfacher, eine Ableitung von Panel durchzuführen, da es schwierig sein kann, die vorhandene Layoutlogik eines Panels zu umgehen, für das bereits ein Layoutverhalten verfügbar ist. Außerdem verfügt ein Panel mit Verhalten möglicherweise über bereits vorhandene Eigenschaften, die nicht für Ihre Panel-Layoutfunktionen relevant sind.

Ihr benutzerdefiniertes Panel erbt von Panel die folgenden APIs:

  • Die Eigenschaft Children
  • Die Eigenschaften Background, ChildrenTransitions und IsItemsHost sowie die Bezeichner von Abhängigkeitseigenschaften Keine dieser Eigenschaften ist virtuell, d. h., Sie müssen sie normalerweise nicht überschreiben oder ersetzen. In der Regel benötigen Sie diese Eigenschaften nicht für benutzerdefinierte Panelszenarien, noch nicht einmal zum Lesen von Werten.
  • Das Layout überschreibt die Methoden MeasureOverride und ArrangeOverride. Diese wurden ursprünglich durch FrameworkElement definiert. Die Panel-Basisklasse überschreibt diese Methoden nicht. Praktische Panels wie Grid weisen jedoch Überschreibungsimplementierungen auf, die als systemeigener Code implementiert und vom System ausgeführt werden. Der Hauptaufwand bei der Definition eines benutzerdefinierten Panels besteht in der Bereitstellung von neuen (oder zusätzlichen) Implementierungen für ArrangeOverride und MeasureOverride.
  • Alle anderen APIs von FrameworkElement, UIElement und DependencyObject, wie Height, Visibility usw. Sie verweisen in Ihren Layoutüberschreibungen manchmal auf Werte dieser Eigenschaften. Da diese jedoch nicht virtuell sind, überschreiben oder ersetzen Sie diese in der Regel nicht.

Hier werden XAML-Layoutkonzepte beschrieben, sodass Sie alle Möglichkeiten berücksichtigen können, wie sich ein benutzerdefiniertes Panel im Layout verhalten kann und verhalten sollte. Wenn Sie direkt beginnen möchten und sich ein Beispiel für eine benutzerdefinierte Panelimplementierung ansehen möchten, finden Sie weitere Informationen unter „BoxPanel“, ein Beispiel für eine benutzerdefinierte Panelimplementierung.

Die Eigenschaft Children

Die Eigenschaft Children ist für benutzerdefinierte Panel relevant, da alle Klassen, die von Panel abgeleitet werden, die Eigenschaft Children verwenden, um die in ihnen enthaltenen untergeordneten Elemente in einer Sammlung zu speichern. Children ist als XAML-Inhaltseigenschaft für die Klasse Panel festgelegt, und alle von Panel abgeleiteten Klassen können das XAML-Inhaltseigenschaftsverhalten erben. Wenn eine Eigenschaft als XAML-Inhaltseigenschaft festgelegt ist, bedeutet das, dass das XAML-Markup ein Eigenschaftenelement auslassen kann, wenn diese Eigenschaft im Markup angegeben wird. Die Werte werden als unmittelbare untergeordnete Markupelemente (der „Inhalt“) festgelegt. Wenn Sie beispielsweise eine Klasse mit dem Namen CustomPanel von Panel ableiten, die kein neues Verhalten definiert, können Sie dennoch dieses Markup verwenden:

<local:CustomPanel>
  <Button Name="button1"/>
  <Button Name="button2"/>
</local:CustomPanel>

Wenn ein XAML-Parser dieses Markup liest, ist Children als die XAML-Inhaltseigenschaft für alle von Panel abgeleiteten Typen bekannt. Daher fügt der Parser die beiden Button-Elemente dem UIElementCollection-Wert der Children-Eigenschaft hinzu. Die XAML-Inhaltseigenschaft ermöglicht im XAML-Markup optimierte Beziehungen zwischen übergeordneten und untergeordneten Elementen für eine Benutzeroberflächendefinition. Weitere Informationen zu XAML-Inhaltseigenschaften und zur Auffüllung von Sammlungseigenschaften während der XAML-Analyse finden Sie in der Anleitung zur XAML-Syntax.

Der Sammlungstyp, der den Wert der Eigenschaft Children beibehält, ist die UIElementCollection-Klasse. UIElementCollection ist eine stark typisierte Sammlung, die UIElement als erzwungenen Elementtyp verwendet. UIElement ist ein Basistyp, der von Hunderten von praktischen Benutzeroberflächen-Elementtypen geerbt wird. Daher ist die Typerzwingung hier absichtlich locker. Er erzwingt jedoch, dass es nicht möglich ist, ein Brush als direktes untergeordnetes Element eines Panel zu verwenden. Allgemein bedeutet das, dass nur Elemente, die in der Benutzeroberfläche sichtbar und Bestandteil des Layouts sein werden, als untergeordnete Elemente in einem Panel gefunden werden.

In der Regel akzeptiert ein benutzerdefiniertes Panel jedes untergeordnete UIElement-Element gemäß einer XAML-Definition, indem einfach die unveränderten Merkmale der Children-Eigenschaft verwendet werden. Als erweitertes Szenario wäre eine Unterstützung einer weiteren Typüberprüfung der untergeordneten Elemente möglich, wenn Sie die Sammlung in Ihren Layoutüberschreibungen durchlaufen.

Neben Schleifen durch die Children-Sammlung in den Überschreibungen könnte Ihre Panellogik auch durch Children.Count beeinflusst werden. Vielleicht verwenden Sie eine Logik, die Speicherplatz zumindest teilweise auf der Grundlage der Anzahl der Elemente zuordnet, statt auf Grundlage der gewünschten Größen und den anderen Eigenschaften der einzelnen Elemente.

Überschreiben der Layoutmethoden

Das Basismodell für die Methoden zur Layoutüberschreibung (MeasureOverride und ArrangeOverride) besteht darin, dass sie alle untergeordneten Elemente durchlaufen und die spezifische Layout-Methode der einzelnen untergeordneten Elemente aufrufen. Der erste Layoutzyklus beginnt, wenn das XAML-Layoutsystem das Layout für das Stammfenster festlegt. Da jedes übergeordnete Element das Layout der jeweiligen untergeordneten Elemente aufruft, wird dadurch der Aufruf von Layout-Methoden für jedes mögliche UI-Element propagiert, das Teil des Layouts sein soll. Im XAML-Layout gibt es zwei Stufen: Messung und anschließend Anordnung.

Sie erhalten keine integrierten Layoutmethoden-Verhaltensweisen für MeasureOverride und ArrangeOverride von der Basisklasse Panel. Elemente in Children werden nicht automatisch als Teil der visuellen XAML-Struktur gerendert. Sie müssen die Elemente dem Layoutprozess bekanntmachen, indem Sie für jedes Element, das Sie in Children finden, über eine Layoutübergabe innerhalb Ihrer MeasureOverride- und ArrangeOverride-Implementierungen Layoutmethoden aufrufen.

Es gibt keinen Grund, Basisimplementierungen in Layoutüberschreibungen aufzurufen, wenn Sie Ihr eigenes Vererbungsmuster nutzen können. Die nativen Methoden zum Layoutverhalten (sofern vorhanden) werden unabhängig davon ausgeführt. Selbst wenn Sie keine Basisimplementierung von Überschreibungen aufrufen, können Sie nicht verhindern, dass das native Verhalten ausgeführt wird.

Während der Übergabe der Messwerte fragt Ihre Layoutlogik alle untergeordneten Elemente in Bezug auf die gewünschte Größe ab, indem sie die Measure-Methode für die untergeordneten Elemente aufruft. Durch den Aufruf der Measure-Methode wird der Wert für die Eigenschaft DesiredSize festgelegt. Der MeasureOverride-Rückgabewert gibt die gewünschte Größe für das Panel selbst an.

Während der Anordnungsübergabe werden die Positionen und Größen der untergeordneten Elemente im x-y-Raum bestimmt, und die Zusammensetzung des Layouts wird für die Darstellung vorbereitet. Ihr Code muss Arrange für jedes untergeordnete Element in Children aufrufen, damit das Layoutsystem erkennt, dass das Element zum Layout gehört. Der Aufruf von Arrange ist eine Vorstufe für die Zusammensetzung und das Rendering. Hierdurch wird Layoutsystem darüber informiert, welche Position das Element erhält, wenn die Zusammensetzung für die Darstellung übermittelt wird.

Viele Eigenschaften und Werte haben Einfluss darauf, wie die Layoutlogik zur Laufzeit ausgeführt wird. Sie können sich den Layoutprozess z. B. so vorstellen, dass die Elemente ohne untergeordnete Elemente (in der Regel das Element der tiefsten Schachtelungsebene in der Benutzeroberfläche) diejenigen sind, die die Messungen zuerst abschließen. Diese Elemente sind nicht von untergeordneten Elementen abhängig, die Einfluss auf die gewünschte Größe dieser Elemente haben können. Sie können ihre eigenen gewünschten Größen haben. Es handelt sich dabei um Größenvorschläge, bis das Layout tatsächlich erfolgt. Dann, bei der Übergabe der Messwerte, wird die visuelle Struktur durchlaufen, bis das Stammelement die erforderlichen Maße hat und die Messungen abgeschlossen werden können.

Das Kandidatenlayout muss in das aktuelle App-Fenster passen, ansonsten werden Teile der Benutzeroberfläche abgeschnitten. Die Beschneidungslogik wird häufig in Panels festgelegt. Die Panellogik kann bestimmen, welche Größe aufgrund der MeasureOverride-Implementierung verfügbar ist, und muss möglicherweise die Größeneinschränkungen an die untergeordneten Elemente weitergeben und den verfügbaren Platz auf die untergeordneten Elemente aufteilen, damit alle Elemente so gut wie möglich passen. Das Ergebnis des Layouts fällt im Idealfall so aus, dass die verschiedene Eigenschaften aller Teile des Layouts verwendet werden und dennoch in das Anwendungsfenster passen. Dazu ist nicht nur eine gute Implementierung der Layoutlogik der Panels erforderlich, sondern auch ein vernünftiges Benutzeroberflächendesign seitens des App-Codes, mit dem eine Benutzeroberfläche mit diesem Panel erstellt wird. Das Paneldesign wird nicht gut aussehen, wenn im gesamten UI-Design mehr untergeordnete Elemente enthalten sind, als überhaupt in die App passen.

Das Layoutsystem funktioniert also hauptsächlich deshalb, weil jedes Element, das auf dem FrameworkElement basiert, bereits ein eigenes inhärentes Verhalten aufweist, wenn es als untergeordnetes Element in einem Container verwendet wird. So gibt es beispielsweise mehrere APIs von FrameworkElement, die entweder über das Layoutverhalten informieren oder benötigt werden, damit das Layout überhaupt funktionieren kann. Dazu gehören:

MeasureOverride

Die MeasureOverride-Methode hat einen Rückgabewert, der vom Layoutsystem als Ausgangspunkt fürDesiredSize für das Panel selbst verwendet wird, wenn die Measure-Methode im Panel durch das übergeordnete Element im Layout aufgerufen wird. Die logischen Entscheidungen innerhalb der Methode sind genauso wichtig wie die zurückgegebenen Werte, und die Logik hat häufig Einfluss darauf, welche Werte zurückgegeben werden.

Alle MeasureOverride-Implementierungen sollten Children als Schleife durchlaufen und die Measure-Methode für jedes untergeordnete Element aufrufen. Durch den Aufruf der Measure-Methode wird der Wert für die Eigenschaft DesiredSize festgelegt. Dies könnte als Information dafür verwendet werden, wie viel Platz das Panel selbst benötigt und wie dieser Platz für die einzelnen Elementen aufgeteilt oder für ein bestimmtes untergeordnetes Element bemessen wird.

Im Folgenden wird ein sehr einfaches Grundgerüst einer MeasureOverride-Methode gezeigt:

protected override Size MeasureOverride(Size availableSize)
{
    Size returnSize; //TODO might return availableSize, might do something else
     
    //loop through each Child, call Measure on each
    foreach (UIElement child in Children)
    {
        child.Measure(new Size()); // TODO determine how much space the panel allots for this child, that's what you pass to Measure
        Size childDesiredSize = child.DesiredSize; //TODO determine how the returned Size is influenced by each child's DesiredSize
        //TODO, logic if passed-in Size and net DesiredSize are different, does that matter?
    }
    return returnSize;
}

Elemente haben zum Zeitpunkt, zu dem sie für das Layout bereitstehen, häufig eine natürliche Größe. Nach dem Messdurchlauf gibt DesiredSize möglicherweise diese natürliche Größe an, wenn die von Ihnen übergebene availableSize für Measure kleiner war. Wenn die natürliche Größe größer als die availableSize ist, die Sie für Measure übergeben haben, wird die DesiredSize auf die availableSize eingeschränkt. So funktioniert auch die interne Implementierung von Measure. Dieses Verhalten muss bei Ihren Layoutüberschreibungen berücksichtigt werden.

Einige Elemente haben keine natürliche Größe, da sie Auto-Werte für Height und Width besitzen. Diese Elemente verwenden die gesamte availableSize, da ein Auto-Wert dazu dient, die Größe eines Elements auf die maximal verfügbare Größe festzulegen. Diese wird durch das unmittelbar übergeordnete Layoutelement durch den Aufruf von Measure mit availableSize mitgeteilt. In der Praxis gibt es stets einen Messwert, an den die Größe einer Benutzeroberfläche angepasst wird (auch wenn es sich um das Hauptfenster handelt.) Schließlich löst die Messwertübergabe anhand der Einschränkungen des übergeordneten Elements alle Auto-Werte auf, und alle Auto-Werte erhalten reale Messwerte (die Sie durch Prüfen von ActualWidth und ActualHeight nach Abschluss des Layouts abrufen können).

Es ist zulässig, an Measure eine Größe mit mindestens einer unendlichen Dimension zu übergeben, um anzuzeigen, dass das Panel versuchen kann, seine Größe unabhängig vom Inhalt selbst anzupassen. Jedes gemessene untergeordnete Element legt seinen DesiredSize-Wert auf seine natürliche Größe fest. Während des Anordnungsdurchlaufs wird das Panel in der Regel unter Verwendung dieser Größe angeordnet.

Textelemente wie TextBlock weisen auf Grundlage ihrer Textzeichenfolge und -eigenschaften eine berechnete ActualWidth und ActualHeight auf. Dies gilt selbst dann, wenn keine Werte für Height oder Width festgelegt sind. Diese Dimensionen sollten in Ihrer Panellogik berücksichtigt werden. Die Beschneidung von Text wirkt sich besonders negativ auf die Benutzerfreundlichkeit einer UI aus.

Auch wenn Ihre Implementierung nicht die gewünschten Größenmesswerte verwendet, sollten Sie die Measure-Methode für jedes untergeordnete Element aufrufen, da interne und systemeigene Verhaltensweisen vorhanden sind, die durch den Aufruf von Measure ausgelöst werden. Damit ein Element Teil eines Layouts sein kann, muss für jedes untergeordnete Element während des Messdurchlaufs Measure und während des Anordnungsdurchlaufs die Methode Arrange aufgerufen werden. Durch den Aufruf dieser Methoden werden interne Kennzeichen für das Objekt festgelegt und Werte (beispielsweise die Eigenschaft DesiredSize) aufgefüllt, die die Layoutlogik des Systems benötigt, wenn die visuelle Struktur erstellt und die Benutzeroberfläche gerendert werden.

Der Rückgabewert von MeasureOverride basiert auf der logischen Interpretation des Panels von DesiredSize oder anderen Größenaspekten für die einzelnen untergeordneten Elemente in Children, wenn Measure für diese aufgerufen wird. Es ist der Interpretation durch Ihre Logik überlassen, wie DesiredSize-Werte untergeordneter Elemente behandelt werden und wie der MeasureOverride-Rückgabewert diese verwenden soll. In der Regel werden die Werte nicht unverändert hinzugefügt, da der Eingabewert von MeasureOverride häufig eine feste verfügbare Größe ist, die vom übergeordneten Element des Panels vorgeschlagen wird. Wenn Sie diese Größe überschreiten, kann das Panel selbst abgeschnitten werden. Sie würden normalerweise die Gesamtgröße der untergeordneten Elemente mit der tatsächlich verfügbaren Größe des Panels vergleichen und ggf. Anpassungen vornehmen.

Tipps und Richtlinien

  • Im Idealfall sollte ein benutzerdefiniertes Panel als erste echte visuelle Struktur in einer Benutzeroberflächenzusammenstellung geeignet sein, vielleicht auf der Ebene unmittelbar unter Page, UserControl oder einem anderen Element, das als Stamm der XAML-Seite fungiert. In MeasureOverride-Implementierungen darf die Eingabe Size nicht routinemäßig zurückgegeben werden, ohne dass eine Überprüfung der Werte erfolgt. Wenn die zurückgegebene Size einen Infinity-Wert enthält, können in der Runtime-Layoutlogik Ausnahmen ausgelöst werden. Ein Infinity-Wert kann aus dem App-Hauptfenster stammen, da dieses bildlauffähig ist und deshalb keine maximale Höhe aufweist. Andere bildlauffähige Inhalte können ein ähnliches Verhalten aufweisen.
  • Ein weiterer häufiger Fehler in MeasureOverride-Implementierungen besteht darin, dass ein neuer Standardwert für Size zurückgegeben wird (Werte für Höhe und Breite sind 0). Sie beginnen möglicherweise mit diesem Wert, und es ist möglicherweise sogar der richtige Wert, wenn Ihr Panel ermittelt, dass keines der untergeordneten Elemente gerendert werden soll. Ein Standardwert für Size führt jedoch dazu, dass Ihr Panel auf dem Hostgerät nicht die richtige Größe hat. Da das Panel keinen Platz auf der Benutzeroberfläche anfordert, erhält es auch keinen Platz und wird nicht gerendert. Obwohl Ihr gesamter Panelcode in anderer Hinsicht optimal funktioniert, wird das Panel oder dessen Inhalt nicht angezeigt, wenn als Höhe und Breite ein Nullwert angegeben wird.
  • Verzichten Sie in Überschreibungen darauf, untergeordnete Elemente in FrameworkElement umzuwandeln und Eigenschaften zu verwenden, die als Ergebnis des Layouts berechnet werden. Dies gilt insbesondere für ActualWidth und ActualHeight. In den meisten gängigen Szenarien können Sie die Logik auf den DesiredSize-Wert des untergeordneten Elements stützen und benötigen keine auf Height oder Width bezogenen Eigenschaften des untergeordneten Elements. Sie können die speziellen Informationen Ihres Elements für besondere Fälle nutzen, in denen Sie den Elementtyp kennen und über zusätzliche Informationen verfügen (beispielsweise die natürliche Größe einer Bilddatei), da es sich nicht um einen Wert handelt, der aktiv von den Layoutsystemen geändert wird. Das Einbinden von layoutberechneten Eigenschaften als Teil der Layoutlogik steigert deutlich das Risiko, unbeabsichtigt eine Layoutschleife zu definieren. Diese Schleifen verursachen einen Zustand, in dem kein gültiges Layout erstellt werden kann. Bei einer nicht behebbaren Schleife kann das System eine LayoutCycleException auslösen.
  • Panels teilen den verfügbaren Platz in der Regel zwischen mehreren untergeordneten Elementen auf. Die genaue Aufteilung ist jedoch unterschiedlich. So implementiert beispielsweise Grid eine Layoutlogik, die mit den Werten RowDefinition und ColumnDefinition den Raum in Grid-Zellen aufteilt. Dabei werden sowohl Größenanpassungen mit Sternvariablen als auch Pixelwerte unterstützt. Bei Pixelwerten ist die Größe, die für jedes untergeordnete Element zur Verfügung steht, bereits bekannt. Diese Werte können also als Eingangsgröße für ein Measure im Rasterstil weitergegeben werden.
  • Panels selbst können reservierten Platz als Abstand zwischen einzelnen Elementen verwenden. Wenn Sie diese Möglichkeit nutzen, müssen Sie die Messwerte als eine Eigenschaft bereitstellen, die sich von Margin oder anderen Padding-Eigenschaften unterscheidet.
  • Elemente können Werte für ihre Eigenschaften ActualWidth und ActualHeight auf der Basis eines früheren Layoutdurchlaufs aufweisen. Wenn sich Werte ändern, kann der Benutzeroberflächencode der App Handler für LayoutUpdated auf Elemente anwenden, wenn eine bestimmte Logik ausgeführt werden soll ist. Die Panellogik muss jedoch in der Regel keine Prüfung auf Änderungen mittels Ereignisbehandlung durchführen. Das Layoutsystem legt bereits fest, wann das Layout erneut ausgeführt werden soll, weil sich der Wert einer layoutrelevanten Eigenschaft geändert hat, und die Panelmethoden MeasureOverride oder ArrangeOverride werden jeweils automatisch aufgerufen.

ArrangeOverride

Die ArrangeOverride-Methode hat einen Rückgabewert Size, der vom Layoutsystem verwendet wird, wenn das Panel selbst gerendert wird, wenn die Arrange-Methode im Panel durch das übergeordnete Element im Layout aufgerufen wird. Es ist typisch, dass der Eingangswert finalSize und der von ArrangeOverride zurückgegebene Wert für Size identisch sind. Wenn sie es nicht sind, bedeutet dies, dass das Panel versucht, eine andere Größe zu verwenden als die, die für die anderen Teilnehmer bei der Layoutbeanspruchung verfügbar ist. Die endgültige Größe basierte auf der Voraussetzung, dass zuvor die Übergabe der Messwerte für das Layout durch Ihren Panelcode ausgeführt wurde. Aus diesem Grund lässt sich erklären, weshalb normalerweise keine andere Größe zurückgegeben wird: Sie würden bewusst die Messwertelogik ignorieren.

Geben Sie keine Size mit einer Infinity-Komponente zurück. Wenn Sie versuchen, eine solche Size zu verwenden, wird über das interne Layout eine Ausnahme ausgelöst.

Alle ArrangeOverride-Implementierungen sollten Children als Schleife durchlaufen und die Arrange-Methode für jedes untergeordnete Element aufrufen. Wie Measure hat auch Arrange keinen Rückgabewert. Im Gegensatz zu Measure wird keine berechnete Eigenschaft als Ergebnis festgelegt. (Das betreffende Element löst jedoch in der Regel ein LayoutUpdated-Ereignis aus.)

Im Folgenden wird ein sehr einfaches Grundgerüst einer ArrangeOverride-Methode gezeigt:

protected override Size ArrangeOverride(Size finalSize)
{
    //loop through each Child, call Arrange on each
    foreach (UIElement child in Children)
    {
        Point anchorPoint = new Point(); //TODO more logic for topleft corner placement in your panel
       // for this child, and based on finalSize or other internal state of your panel
        child.Arrange(new Rect(anchorPoint, child.DesiredSize)); //OR, set a different Size 
    }
    return finalSize; //OR, return a different Size, but that's rare
}

Die Anordnungsübergabe für das Layout kann erfolgen, ohne dass zuvor eine Übergabe der Messwerte stattgefunden hat. Dies geschieht aber nur, wenn das Layoutsystem festgestellt hat, dass sich keine Eigenschaften geändert haben, die sich auf vorherige Messungen auswirken. Beispielsweise muss bei einer geänderten Ausrichtung das betreffende Element nicht erneut gemessen werden, da sich dessen DesiredSize durch die Änderung der Ausrichtung nicht ändern würde. Wenn sich jedoch ActualHeight für ein beliebiges Element in einem Layout ändern würde, wäre ein neuer Messdurchlauf notwendig. Das Layoutsystem erkennt echte Messswertänderungen automatisch, ruft den Messdurchlauf erneut auf und führt dann einen neuen Anordnungsdurchlauf aus.

Die Eingabe für Arrange verwendet einen Rect-Wert. Die am häufigsten für die Konstruktion dieses Rect verwendete Methode besteht in der Verwendung des Konstruktors, der Eingabewerte für Point und Size hat. Der Point ist der Punkt, an dem die obere linke Ecke des Begrenzungsrahmens für das Element platziert werden soll. Die Size sind die Dimensionen, die zum Rendern dieses spezifischen Elements verwendet werden. Häufig wird die DesiredSize für dieses Element als dieser Size-Wert verwendet, da die Festlegung von DesiredSize für alle im Layout enthaltenen Elemente der Zweck des Messdurchlaufs für das Layout war. (Die Übergabe der Messwerte bestimmt die gesamte Dimensionierung der Elemente auf iterative Weise, sodass das Layoutsystem die Platzierung der Elemente optimieren kann, sobald die Anordnungsübergabe erreicht ist.)

Bei den ArrangeOverride-Implementierungen unterscheidet sich typischerweise die Logik, mit der das Panel die Point-Komponente bestimmt, d. h., wie die einzelnen untergeordneten Elemente angeordnet werden. Ein Panel mit absoluter Positionierung, beispielsweise Canvas, verwendet die ausdrücklichen Platzierungsinformationen, die es von den einzelnen Elementen über die Canvas.Left- Canvas.Top-Werte erhält. Ein raumtrennendes Panel, beispielsweise Grid, verwendet mathematische Operationen, durch die der verfügbare Raum in Zellen unterteilt wird. Jede Zelle verfügt über einen x-y-Wert, um zu definieren, an welcher Position die Inhalte der Zelle platziert und angeordnet werden sollen. Ein adaptives Panel, beispielsweise StackPanel, kann sich möglicherweise selbst erweitern, um den Inhalt an die Ausrichtungsabmessungen des Panels anzupassen.

Neben der direkten Steuerung und Weitergabe an Arrange gibt es noch weitere Aspekte, von denen die Positionierung von Elementen im Layout beeinflusst wird. Diese resultieren aus der internen systemeigenen Implementierung von Arrange, die allen von FrameworkElement abgeleiteten Typen gemeinsam ist, und werden durch einige andere Typen wie Textelemente ergänzt. So können z. B. Elemente einen Rand und eine Ausrichtung haben, und einige können auch einen Abstand aufweisen. Diese Eigenschaften stehen oft in Interaktion. Weitere Informationen hierzu finden Sie unter Ausrichtung, Rand und Abstand.

Panels und Steuerelemente

Vermeiden Sie es, Funktionen in ein benutzerdefiniertes Panel zu implementieren, die stattdessen in einem benutzerdefiniertem Steuerelement erstellt werden sollten. Die Rolle eines Panels besteht darin, alle enthaltenden Inhalte untergeordneter Elemente darzustellen – und zwar als Layoutfunktion, die automatisch erfolgt. Das Panel fügt dem Inhalt möglicherweise Dekorationen hinzu (ähnlich wie ein Border den Rand um das Element ergänzt, das es darstellt) oder führt andere layoutbezogene Anpassungen aus, beispielsweise eine Auffüllung. So weit sollten Sie jedoch gehen, wenn Sie die Ausgabe der visuellen Struktur über die Berichterstattung und Verwendung der Informationen der untergeordneten Elemente hinaus erweitern möchten.

Wenn es eine Interaktion gibt, auf die der Benutzer Zugriff hat, sollten Sie ein benutzerdefiniertes Steuerelement definieren – kein Panel. So sollte ein Panel beispielsweise keine Viewports für den Bildlauf zu den Inhalten, die es darstellt, hinzufügen, selbst wenn das Ziel darin besteht, ein Abschneiden zu verhindern, denn Bildlaufleisten, Ziehpunkte etc. sind interaktive Steuerelemente. (Der Inhalt verfügt möglicherweise über Bildlaufleisten, aber Sie sollten dies der Logik des untergeordneten Elements überlassen. Erzwingen Sie dies nicht, indem Sie einen Bildlauf als Layoutvorgang hinzufügen.) Sie können ein Steuerelement erstellen und auch einen benutzerdefinierten Bereich schreiben, der eine wichtige Rolle in der visuellen Struktur dieses Steuerelements spielt, wenn es um die Darstellung von Inhalten in diesem Steuerelement geht. Das Steuerelement und das Panel sollten jedoch unterschiedliche Code-Objekte sein.

Ein Grund dafür: Die Unterscheidung zwischen Steuerelement und Panel ist für die Microsoft-Benutzeroberflächenautomatisierung und Barrierefreiheit wichtig. Panels stellen ein visuelles Layoutverhalten bereit, kein logisches Verhalten. Die visuelle Darstellung eines UI-Elements ist in der Regel kein wichtiger UI-Aspekt in Barrierefreiheitsszenarien. Bei der Barrierefreiheit geht es darum, die Teile einer App verfügbar zu machen, die für das Verständnis der UI-Logik wichtig sind. Wenn Interaktion erforderlich ist, sollten Steuerelemente die Interaktionsmöglichkeiten in der Benutzeroberflächenautomatisierungs-Infrastruktur bereitstellen. Weitere Informationen finden Sie unter Benutzerdefinierte Automatisierungspeers.

Andere Layout-APIs

Es gibt einige weitere APIs, die Teil des Layoutsystems sind, jedoch nicht durch Panel deklariert werden. Einige von ihnen könnten in einer Panelimplementierung oder in einem benutzerdefinierten Steuerelement verwendet werden, das Panels nutzt.

  • UpdateLayout, InvalidateMeasure und InvalidateArrange sind Methoden, die einen Layoutdurchlauf initiieren. InvalidateArrange löst möglicherweise keinen Messdurchlauf aus, die beiden anderen Methoden tun dies jedoch. Diese Methoden dürfen niemals aus einer Layoutmethodenüberschreibung heraus aufgerufen werden, da sie mit großer Wahrscheinlichkeit zu einer Layoutschleife führen. Vom Steuerelementcode müssen sie normalerweise auch nicht aufgerufen werden. Die meisten Layoutaspekte werden automatisch ausgelöst, indem Änderungen in den vom Framework definierten Layouteigenschaften wie Width usw. erkannt werden.
  • LayoutUpdated ist ein Ereignis, das ausgelöst wird, wenn sich ein Layoutaspekt des Elements ändert. Das ist nicht spezifisch für Panels; das Ereignis wird durch das FrameworkElement definiert.
  • SizeChanged ist ein Ereignis, das nur ausgelöst wird, wenn die Layoutdurchläufe abgeschlossen sind. Es gibt an, dass sich ActualHeight oder ActualWidth geändert haben. Dies ist ein weiteres FrameworkElement-Ereignis. Es gibt Fälle, in denen LayoutUpdated ausgelöst wird, SizeChanged hingegen nicht. Beispielsweise könnten die internen Inhalte neu angeordnet werden, ohne dass sich die Größe des Elements ändert.

Referenz

Konzepte