Freigeben über


Übersicht über benutzerdefinierte XAML-Panels

Ein Panel ist ein Objekt, das ein Layoutverhalten für untergeordnete Elemente bereitstellt, das sie enthält, wenn das XAML-Layoutsystem (Extensible Application Markup Language) ausgeführt wird und die App-UI gerendert wird.

Wichtige APIs: Panel, ArrangeOverride, MeasureOverride

Sie können benutzerdefinierte Panels für das XAML-Layout definieren, indem Sie eine benutzerdefinierte Klasse von der Panel-Klasse ableiten. Sie stellen Verhalten für Ihren Bereich bereit, indem Sie die MeasureOverride und ArrangeOverride außer Kraft setzen und Logik bereitstellen, die die untergeordneten Elemente misst und anordnet.

Die Panel-Basisklasse

Um eine benutzerdefinierte Panelklasse zu definieren, können Sie entweder direkt von der Panel-Klasse abgeleitet oder von einer der praktischen Panelklassen abgeleitet werden, die nicht versiegelt sind, z. B. Grid oder StackPanel. Es ist einfacher, von Panel abzuleiten, da es schwierig sein kann, die vorhandene Layoutlogik eines Panels zu umgehen, das bereits ein Layoutverhalten aufweist. Darüber hinaus verfügt ein Panel mit Verhalten möglicherweise über vorhandene Eigenschaften, die für die Layoutfeatures Ihres Panels nicht relevant sind.

Aus Panel erbt Ihr benutzerdefiniertes Panel die folgenden APIs:

  • Die Children-Eigenschaft.
  • Die Eigenschaften "Background", "ChildrenTransitions" und "IsItemsHost" und die Bezeichner der Abhängigkeitseigenschaft. Keine dieser Eigenschaften ist virtuell, sodass Sie sie in der Regel nicht außer Kraft setzen oder ersetzen. Normalerweise benötigen Sie diese Eigenschaften nicht für benutzerdefinierte Panelszenarien, nicht einmal zum Lesen von Werten.
  • Die Layoutüberschreibungsmethoden MeasureOverride und ArrangeOverride. Diese wurden ursprünglich von FrameworkElement definiert. Die Basispanel-Klasse überschreibt diese nicht, praktische Panels wie Grid verfügen jedoch über Außerkraftsetzungsimplementierungen, die als systemeigener Code implementiert werden und vom System ausgeführt werden. Die Bereitstellung neuer (oder additiver) Implementierungen für ArrangeOverride und MeasureOverride ist der Großteil des Aufwands, den Sie zum Definieren eines benutzerdefinierten Panels benötigen.
  • Alle anderen APIs von FrameworkElement, UIElement und DependencyObject, z. B. Height, Visibility usw. Sie verweisen manchmal auf Werte dieser Eigenschaften in Ihren Layoutüberschreibungen, aber sie sind nicht virtuell, sodass Sie sie in der Regel nicht außer Kraft setzen oder ersetzen.

Dieser Fokus liegt hier auf der Beschreibung von XAML-Layoutkonzepten, sodass Sie alle Möglichkeiten berücksichtigen können, wie ein benutzerdefiniertes Panel sich im Layout verhalten kann und verhalten sollte. Wenn Sie lieber direkt nach rechts springen und ein Beispiel für eine benutzerdefinierte Panelimplementierung sehen möchten, lesen Sie BoxPanel, ein Beispiel für ein benutzerdefiniertes Panel.

Die Children-Eigenschaft

Die Children-Eigenschaft ist für ein benutzerdefiniertes Panel relevant, da alle von Panel abgeleiteten Klassen die Children-Eigenschaft als Ort zum Speichern ihrer enthaltenen untergeordneten Elemente in einer Auflistung verwenden. Untergeordnete Elemente werden als XAML-Inhaltseigenschaft für die Panel-Klasse festgelegt, und alle von Panel abgeleiteten Klassen können das VERHALTEN der XAML-Inhaltseigenschaft erben. Wenn eine Eigenschaft als XAML-Inhaltseigenschaft festgelegt ist, bedeutet dies, dass XAML-Markup ein Eigenschaftselement weglassen kann, wenn diese Eigenschaft im Markup angegeben wird, und 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 dieses Markup weiterhin verwenden:

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

Wenn ein XAML-Parser dieses Markup liest, ist Children als XAML-Inhaltseigenschaft für alle abgeleiteten Paneltypen bekannt, sodass der Parser die beiden Button-Elemente dem UIElementCollection-Wert der Children-Eigenschaft hinzu fügt. Die XAML-Inhaltseigenschaft erleichtert eine optimierte Beziehung zwischen übergeordneten und untergeordneten Elementen im XAML-Markup für eine UI-Definition. Weitere Informationen zu XAML-Inhaltseigenschaften und zur Auffüllung von Sammlungseigenschaften beim Analysieren von XAML finden Sie im XAML-Syntaxhandbuch.

Der Sammlungstyp, der den Wert der Children-Eigenschaft aufrecht erhält, ist die UIElementCollection-Klasse. UIElementCollection ist eine stark typierte Auflistung, die UIElement als erzwungenen Elementtyp verwendet. UIElement ist ein Basistyp, der von Hunderten praktischer UI-Elementtypen geerbt wird, sodass die Typerzwingung hier absichtlich locker ist. Sie erzwingt jedoch, dass Sie keinen Pinsel als direktes untergeordnetes Element eines Panels haben können. Dies bedeutet im Allgemeinen, dass nur Elemente angezeigt werden, die in der Benutzeroberfläche sichtbar sein und am Layout teilnehmen, als untergeordnete Elemente in einem Panel gefunden werden.

In der Regel akzeptiert ein benutzerdefiniertes Panel jedes untergeordnete UIElement-Element anhand einer XAML-Definition, indem einfach die Merkmale der Children-Eigenschaft verwendet werden. Als erweitertes Szenario können Sie die weitere Typüberprüfung untergeordneter Elemente unterstützen, wenn Sie die Sammlung in Ihren Layoutüberschreibungen durchlaufen.

Neben der Schleife durch die Children-Auflistung in den Außerkraftsetzungen kann ihre Panellogik auch beeinflusst Children.Countwerden. Möglicherweise weisen Sie Logik auf, die den Platz zumindest teilweise auf der Grundlage der Anzahl der Elemente angibt, anstatt die gewünschten Größen und die anderen Merkmale einzelner Elemente zuzuordnen.

Überschreiben der Layoutmethoden

Das Grundlegende Modell für die Methoden für die Layoutüberschreibung (MeasureOverride und ArrangeOverride) besteht darin, dass sie alle untergeordneten Elemente durchlaufen und die spezifische Layoutmethode jedes untergeordneten Elements aufrufen sollten. Der erste Layoutzyklus beginnt, wenn das XAML-Layoutsystem das visuelle Element für das Stammfenster festlegt. Da jedes übergeordnete Element das Layout für seine untergeordneten Elemente aufruft, wird dadurch ein Aufruf an Layoutmethoden an jedes mögliche UI-Element weitergegeben, das Teil eines Layouts sein soll. Im XAML-Layout gibt es zwei Phasen: Messen und anordnen.

Sie erhalten kein integriertes Layoutmethodenverhalten für MeasureOverride und ArrangeOverride aus der Basispanelklasse. Elemente in untergeordneten Elementen werden nicht automatisch als Teil der visuellen XAML-Struktur gerendert. Es liegt an Ihnen, die Elemente für den Layoutprozess bekannt zu machen, indem Sie Layoutmethoden für jedes der Elemente aufrufen, die Sie in Untergeordneten Elementen finden, durch einen Layoutdurchlauf in Ihren MeasureOverride - und ArrangeOverride-Implementierungen .

Es gibt keinen Grund, Basisimplementierungen in Layoutüberschreibungen aufzurufen, es sei denn, Sie haben ihre eigene Vererbung. Die systemeigenen Methoden für das Layoutverhalten (sofern vorhanden) werden unabhängig davon ausgeführt, und der Aufruf der Basisimplementierung durch Außerkraftsetzungen verhindert nicht, dass das systemeigene Verhalten auftritt.

Während des Messdurchlaufs fragt die Layoutlogik jedes untergeordnete Element nach der gewünschten Größe ab, indem die Measure-Methode für dieses untergeordnete Element aufgerufen wird. Durch Aufrufen der Measure-Methode wird der Wert für die DesiredSize-Eigenschaft festgelegt. Der Rückgabewert "MeasureOverride " ist die gewünschte Größe für das Panel selbst.

Während des Anordnungsdurchlaufs werden die Positionen und Größen untergeordneter Elemente im x-y-Raum bestimmt, und die Layoutkomposition wird für das Rendern vorbereitet. Ihr Code muss "Anordnen" für jedes untergeordnete Element in "Children" aufrufen, damit das Layoutsystem erkennt, dass das Element zum Layout gehört. Der Arrange-Aufruf ist ein Vorläufer der Komposition und des Renderns. Er informiert das Layoutsystem darüber, wo das Element eingefügt wird, wenn die Komposition zum Rendern übermittelt wird.

Viele Eigenschaften und Werte tragen dazu bei, wie die Layoutlogik zur Laufzeit funktioniert. Eine Möglichkeit zum Nachdenken über den Layoutprozess besteht darin, dass die Elemente ohne untergeordnete Elemente (im Allgemeinen das tief geschachtelte Element in der Benutzeroberfläche) die Elemente sind, die zuerst Messungen abschließen können. Sie haben keine Abhängigkeiten von untergeordneten Elementen, die ihre gewünschte Größe beeinflussen. Sie haben möglicherweise ihre eigenen gewünschten Größen, und dies sind Größenvorschläge, bis das Layout tatsächlich stattfindet. Anschließend geht der Messdurchlauf weiter zur visuellen Struktur, bis das Stammelement seine Maße hat und alle Messungen abgeschlossen werden können.

Das Kandidatenlayout muss in das aktuelle App-Fenster passen, sonst werden Teile der Benutzeroberfläche abgeschnitten. Panels sind häufig die Stelle, an der die Beschneidungslogik bestimmt wird. Panellogik kann bestimmen, welche Größe in der MeasureOverride-Implementierung verfügbar ist, und möglicherweise die Größenbeschränkungen auf die untergeordneten Elemente verschieben und den Platz zwischen untergeordneten Elementen teilen müssen, damit alles so gut passt, wie es möglich ist. Das Ergebnis des Layouts ist idealerweise etwas, das verschiedene Eigenschaften aller Teile des Layouts verwendet, aber dennoch in das App-Fenster passt. Dies erfordert sowohl eine gute Implementierung für die Layoutlogik der Panels als auch ein vernünftiges UI-Design auf dem Teil eines App-Codes, der eine Benutzeroberfläche mithilfe dieses Panels erstellt. Kein Paneldesign sieht gut aus, wenn das allgemeine UI-Design mehr untergeordnete Elemente enthält, als in die App passen können.

Ein großer Teil der Funktionsweise des Layoutsystems besteht darin, dass jedes Element, das auf FrameworkElement basiert, bereits ein eigenes inhärentes Verhalten aufweist, wenn es als untergeordnetes Element in einem Container fungiert. Beispielsweise gibt es mehrere APIs von FrameworkElement , die entweder das Layoutverhalten informieren oder erforderlich sind, um die Layoutarbeit überhaupt zu ermöglichen. Dazu gehören:

MeasureOverride

Die MeasureOverride-Methode weist einen Rückgabewert auf, der vom Layoutsystem als Start-DesiredSize für das Panel selbst verwendet wird, wenn die Measure-Methode im Panel durch das übergeordnete Element im Layout aufgerufen wird. Die logischen Auswahlmöglichkeiten innerhalb der Methode sind genauso wichtig wie das, was sie zurückgibt, und die Logik beeinflusst oft, welcher Wert zurückgegeben wird.

Alle MeasureOverride-Implementierungen sollten untergeordnete Elemente durchlaufen und die Measure-Methode für jedes untergeordnete Element aufrufen. Durch Aufrufen der Measure-Methode wird der Wert für die DesiredSize-Eigenschaft festgelegt. Dies kann darüber informiert werden, wie viel Platz das Panel selbst benötigt, und wie dieser Platz zwischen Elementen geteilt oder für ein bestimmtes untergeordnetes Element angepasst wird.

Hier ist ein sehr einfaches Skelett einer MeasureOverride-Methode:

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 oft eine natürliche Größe, wenn sie für das Layout bereit sind. Nach dem Messdurchlauf gibt die DesiredSize möglicherweise an, dass die natürliche Größe, wenn die verfügbare Größe, die Sie für Measure übergeben haben, kleiner war. Wenn die natürliche Größe größer als "availableSize" ist, die Sie für "Measure" übergeben haben, wird die DesiredSize auf "availableSize" beschränkt. So verhält sich die interne Implementierung von Measure, und Ihre Layoutüberschreibungen sollten dieses Verhalten berücksichtigen.

Einige Elemente haben keine natürliche Größe, da sie Autowerte für Höhe und Breite aufweisen. Diese Elemente verwenden die vollständige availableSize,da dies der Fall ist, was ein Auto-Wert darstellt: Größe des Elements auf die maximale verfügbare Größe, die das direkte übergeordnete Layout kommuniziert, indem Measure mit availableSize aufgerufen wird. In der Praxis gibt es immer eine Maßeinheit, auf die eine Benutzeroberfläche angepasst wird (auch wenn dies das Fenster der obersten Ebene ist.) Schließlich löst der Messdurchlauf alle Auto-Werte in übergeordnete Einschränkungen auf, und alle Elemente des automatischen Werts erhalten reale Maße (die Sie abrufen können, indem Sie ActualWidth und ActualHeight überprüfen, nachdem das Layout abgeschlossen ist).

Es ist gesetzlich zulässig, eine Größe an Measure zu übergeben, die mindestens eine unendliche Dimension aufweist, um anzugeben, dass das Panel versuchen kann, die Größe selbst anzupassen, um Maßangaben des Inhalts anzupassen. Jedes zu messende untergeordnete Element legt seinen DesiredSize-Wert mithilfe seiner natürlichen Größe fest. Während des Anordnungsdurchlaufs wird der Bereich in der Regel mit dieser Größe angeordnet.

Textelemente wie TextBlock verfügen über eine berechnete ActualWidth- und ActualHeight-Eigenschaft basierend auf deren Textzeichenfolgen- und Texteigenschaften, auch wenn kein Height- oder Width-Wert festgelegt ist, und diese Dimensionen sollten von der Panellogik beachtet werden. Das Beschneiden von Text ist eine besonders schlechte Benutzeroberfläche.

Auch wenn Ihre Implementierung die gewünschten Größenmessungen nicht verwendet, empfiehlt es sich, die Measure-Methode für jedes untergeordnete Element aufzurufen, da interne und systemeigene Verhaltensweisen vorhanden sind, die durch den Aufruf von Measure ausgelöst werden. Damit ein Element am Layout teilnimmt, muss jedes untergeordnete Element während des Measuredurchlaufs und der Arrange-Methode, die während des Anordnungsdurchlaufs aufgerufen wird, aufgerufen werden. Durch Aufrufen dieser Methoden werden interne Flags für das Objekt festgelegt und Werte (z. B. die DesiredSize-Eigenschaft ) aufgefüllt, die die Layoutlogik des Systems benötigt, wenn sie die visuelle Struktur erstellt und die Benutzeroberfläche rendert.

Der Rückgabewert "MeasureOverride" basiert auf der Logik des Panels, in der die Überlegungen "DesiredSize" oder andere Größenüberlegungen für die einzelnen untergeordneten Elemente in untergeordneten Elementen interpretiert werden, wenn "Measure" aufgerufen wird. Was mit DesiredSize-Werten von untergeordneten Elementen zu tun ist und wie der MeasureOverride-Rückgabewert sie verwenden soll, liegt bei der Interpretation Ihrer eigenen Logik. Normalerweise fügen Sie die Werte nicht ohne Änderung hinzu, da die Eingabe 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, wird das Panel selbst möglicherweise abgeschnitten. Normalerweise vergleichen Sie die Gesamtgröße der untergeordneten Elemente mit der verfügbaren Größe des Panels und nehmen bei Bedarf Anpassungen vor.

Tipps und Anleitungen

  • Im Idealfall sollte ein benutzerdefiniertes Panel geeignet sein, um das erste echte visuelle Element in einer UI-Komposition zu sein, vielleicht auf einer Ebene direkt unter "Page", "UserControl" oder einem anderen Element, das der STAMM der XAML-Seite ist. Geben Sie in MeasureOverride-Implementierungen die Eingabegröße nicht routinemäßig zurück, ohne die Werte zu untersuchen. Wenn die Rückgabegröße einen Infinity-Wert enthält, kann dies Ausnahmen in der Laufzeitlayoutlogik auslösen. Ein Infinity-Wert kann aus dem Hauptfenster der App stammen, das bildlauffähig ist und daher keine maximale Höhe aufweist. Andere bildlauffähige Inhalte weisen möglicherweise dasselbe Verhalten auf.
  • Ein weiterer häufiger Fehler bei MeasureOverride-Implementierungen besteht darin, eine neue Standardgröße zurückzugeben (Werte für Höhe und Breite sind 0). Möglicherweise beginnen Sie mit diesem Wert, und es ist möglicherweise sogar der richtige Wert, wenn Ihr Panel feststellt, dass keiner der untergeordneten Elemente gerendert werden soll. Eine Standardgröße führt jedoch dazu, dass ihr Panel nicht ordnungsgemäß vom Host angepasst wird. Sie fordert keinen Speicherplatz auf der Benutzeroberfläche an und erhält daher keinen Platz und wird nicht gerendert. Der gesamte Panelcode funktioniert andernfalls möglicherweise einwandfrei, aber Sie sehen den Bereich oder inhalt davon nicht, wenn er mit null Höhe, Nullbreite verfasst wird.
  • Vermeiden Sie innerhalb der Außerkraftsetzungen die Versuchung, untergeordnete Elemente in FrameworkElement zu umwandeln und Eigenschaften zu verwenden, die als Ergebnis des Layouts berechnet werden, insbesondere ActualWidth und ActualHeight. In den meisten gängigen Szenarien können Sie die Logik auf dem Wert des untergeordneten Elements "DesiredSize" basieren, und Sie benötigen keine der mit Height oder Width zusammenhängenden Eigenschaften eines untergeordneten Elements. Für spezielle Fälle, in denen Sie den Elementtyp kennen und zusätzliche Informationen haben, z. B. die natürliche Größe einer Bilddatei, können Sie die speziellen Informationen Ihres Elements verwenden, da es sich nicht um einen Wert handelt, der aktiv von Layoutsystemen geändert wird. Das Einschließen von layoutbasierten Eigenschaften als Teil der Layoutlogik erhöht erheblich das Risiko, eine unbeabsichtigte Layoutschleife zu definieren. Diese Schleifen verursachen eine Bedingung, bei der kein gültiges Layout erstellt werden kann, und das System kann eine LayoutCycleException auslösen, wenn die Schleife nicht wiederhergestellt werden kann.
  • Panels teilen ihren verfügbaren Platz in der Regel zwischen mehreren untergeordneten Elementen auf, obwohl genau die Aufteilung des Raums unterschiedlich ist. Grid implementiert z. B. Layoutlogik, die die Werte "RowDefinition" und "ColumnDefinition" verwendet, um den Abstand in die Rasterzellen zu unterteilen, die sowohl die Größenanpassung von Sternen als auch Pixelwerte unterstützen. Wenn sie Pixelwerte sind, ist die für jedes untergeordnete Element verfügbare Größe bereits bekannt, sodass dies als Eingabegröße für ein Measure im Rasterstil übergeben wird.
  • Panels selbst können reservierten Platz für den Abstand zwischen Elementen einführen. Wenn Sie dies tun, stellen Sie sicher, dass die Maße als Eigenschaft verfügbar gemacht werden, die sich von Margin oder einer Padding-Eigenschaft unterscheidet.
  • Elemente verfügen möglicherweise über Werte für ihre ActualWidth- und ActualHeight-Eigenschaften basierend auf einem vorherigen Layoutdurchlauf. Wenn sich Werte ändern, kann app-UI-Code Handler für LayoutUpdated auf Elemente setzen, wenn eine spezielle Logik ausgeführt werden soll, die Panellogik muss jedoch in der Regel nicht auf Änderungen mit der Ereignisbehandlung überprüft werden. Das Layoutsystem bestimmt bereits, wann das Layout erneut ausgeführt werden soll, da ein layoutrelevanter Eigenschaftswert geändert wurde und die MeasureOverride oder ArrangeOverride eines Panels unter den entsprechenden Umständen automatisch aufgerufen werden.

ArrangeOverride

Die ArrangeOverride-Methode weist einen Size-Rückgabewert auf, der vom Layoutsystem beim Rendern des Panels selbst verwendet wird, wenn die Arrange-Methode im Panel durch das übergeordnete Element im Layout aufgerufen wird. Es ist typisch, dass die Eingabe finalSize und die zurückgegebene ArrangeOverride-Größe identisch sind. Wenn dies nicht der Grund ist, bedeutet dies, dass das Panel versucht, sich selbst eine andere Größe zu machen, als die anderen Teilnehmer des Layoutanspruchs verfügbar sind. Die endgültige Größe basiert darauf, dass Sie zuvor den Messdurchlauf des Layouts über den Panelcode ausgeführt haben. Deshalb ist die Rückgabe einer anderen Größe nicht typisch: Es bedeutet, dass Sie die Measurelogik bewusst ignorieren.

Geben Sie keine Größe mit einer Infinity-Komponente zurück. Wenn Sie versuchen, eine solche Größe zu verwenden, wird eine Ausnahme aus dem internen Layout ausgelöst.

Alle ArrangeOverride-Implementierungen sollten untergeordnete Elemente durchlaufen und die Arrange-Methode für jedes untergeordnete Element aufrufen. Wie "Measure" verfügt Arrange nicht über einen 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).

Hier ist ein sehr einfaches Skelett einer ArrangeOverride-Methode:

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
}

Der Anordnungsdurchlauf des Layouts kann passieren, ohne dass ein Measuredurchlauf vorausgeht. Dies geschieht jedoch nur, wenn das Layoutsystem festgestellt hat, dass sich keine Eigenschaften geändert haben, die sich auf die vorherigen Messungen auswirken würden. Wenn sich beispielsweise eine Ausrichtung ändert, muss dieses bestimmte Element nicht erneut gemessen werden, da sich die GewünschteSize nicht ändern würde, wenn sich die Ausrichtungsauswahl ändert. Wenn "ActualHeight" sich dagegen für ein Element in einem Layout ändert, ist ein neuer Measuredurchlauf erforderlich. Das Layoutsystem erkennt automatisch echte Messänderungen und ruft den Messdurchlauf erneut auf und führt dann einen weiteren Anordnungsdurchlauf aus.

Die Eingabe für Arrange akzeptiert einen Rect-Wert . Die am häufigsten verwendete Methode zum Erstellen dieses Rect besteht darin, den Konstruktor zu verwenden, der über eine Punkteingabe und eine Größe-Eingabe verfügt. Der Punkt ist der Punkt, an dem die obere linke Ecke des Begrenzungsfelds für das Element platziert werden soll. Die Größe ist die Größe, die zum Rendern dieses bestimmten Elements verwendet wird. Häufig verwenden Sie die DesiredSize für dieses Element als diesen Size-Wert , da das Einrichten der DesiredSize für alle elemente, die am Layout beteiligt sind, der Zweck des Measuredurchlaufs des Layouts war. (Der Messdurchlauf bestimmt die gesamte Größenanpassung der Elemente auf iterative Weise, sodass das Layoutsystem optimieren kann, wie Elemente platziert werden, sobald sie zum Anordnungsdurchlauf gelangen.)

Was in der Regel zwischen ArrangeOverride-Implementierungen variiert, ist die Logik, mit der das Panel die Punktkomponente bestimmt, wie die einzelnen untergeordneten Elemente angeordnet werden. Ein absoluter Positionierungsbereich wie Canvas verwendet die expliziten Platzierungsinformationen, die es von jedem Element über Canvas.Left und Canvas.Top Werte abruft. Ein Bereich mit Leerraumteilung, z . B. Grid , hätte mathematische Operationen, die den verfügbaren Platz in Zellen aufgeteilt haben, und jede Zelle hätte einen X-Y-Wert, für den der Inhalt platziert und angeordnet werden soll. Ein adaptives Panel wie StackPanel kann sich erweitern, um Inhalte in die Ausrichtungsdimension einzufügen.

Es gibt noch weitere Positionierungseinflüsse auf Elemente im Layout, über das hinaus, was Sie direkt steuern und an Arrange übergeben. Diese stammen aus der internen nativen Implementierung von Arrange, die allen von FrameworkElement abgeleiteten Typen gemeinsam ist und von einigen anderen Typen wie Textelementen erweitert wird. Beispielsweise können Elemente einen Rand und eine Ausrichtung aufweisen, und einige können einen Abstand aufweisen. Diese Eigenschaften interagieren häufig. Weitere Informationen finden Sie unter Ausrichtung, Rand und Abstand.

Panels und Steuerelemente

Vermeiden Sie das Einfügen von Funktionen in ein benutzerdefiniertes Panel, das stattdessen als benutzerdefiniertes Steuerelement erstellt werden soll. Die Rolle eines Panels besteht darin, alle darin enthaltenen untergeordneten Elementinhalte als Funktion des Layouts darzustellen, die automatisch ausgeführt werden. Das Panel kann Inhalten Dekorationen hinzufügen (ähnlich wie ein Rahmen fügt den Rahmen um das dargestellte Element hinzu), oder andere layoutbezogene Anpassungen wie Abstand ausführen. Dies ist jedoch so weit, wie Sie gehen sollten, wenn Sie die visuelle Strukturausgabe über die Berichterstellung hinaus erweitern und Informationen von den untergeordneten Elementen verwenden sollten.

Wenn für den Benutzer eine Interaktion verfügbar ist, sollten Sie ein benutzerdefiniertes Steuerelement und kein Panel schreiben. Beispielsweise sollte ein Panel keine Bildlauf-Viewports zu Inhalten hinzufügen, die es darstellt, auch wenn das Ziel besteht, das Ausschneiden zu verhindern, da die Bildlaufleisten, Daumen usw. interaktive Steuerelementteile sind. (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 ein benutzerdefiniertes Panel schreiben, das eine wichtige Rolle in der visuellen Struktur dieses Steuerelements spielt, wenn es darum geht, Inhalte in diesem Steuerelement darzustellen. Das Steuerelement und das Panel sollten jedoch unterschiedliche Codeobjekte sein.

Ein Grund dafür ist, dass die Unterscheidung zwischen Steuerelement und Panel aufgrund von Microsoft Benutzeroberflächenautomatisierung und Barrierefreiheit wichtig ist. Panels bieten ein visuelles Layoutverhalten, kein logisches Verhalten. Wie ein UI-Element visuell dargestellt wird, ist kein Aspekt der Benutzeroberfläche, der in der Regel für Barrierefreiheitsszenarien wichtig ist. Bei der Barrierefreiheit geht es darum, die Teile einer App verfügbar zu machen, die für das Verständnis einer Benutzeroberfläche logisch wichtig sind. Wenn Interaktion erforderlich ist, sollten Steuerelemente die Interaktionsmöglichkeiten für die Benutzeroberflächenautomatisierung Infrastruktur verfügbar machen. Weitere Informationen finden Sie unter benutzerdefinierte Automatisierungspeers.

Andere Layout-API

Es gibt einige andere APIs, die Teil des Layoutsystems sind, aber nicht von Panel deklariert werden. Sie können diese in einer Panelimplementierung oder in einem benutzerdefinierten Steuerelement verwenden, das Panels verwendet.

  • UpdateLayout, InvalidateMeasure und InvalidateArrange sind Methoden, die einen Layoutdurchlauf initiieren. InvalidateArrange löst möglicherweise keinen Messdurchlauf aus, die anderen beiden Führen jedoch aus. Rufen Sie diese Methoden niemals innerhalb einer Layoutmethodenüberschreibung auf, da sie fast sicher sind, dass sie eine Layoutschleife verursachen. Steuerelementcode muss diese in der Regel auch nicht aufrufen. Die meisten Aspekte des Layouts werden automatisch ausgelöst, indem Änderungen an den frameworkdefinierten Layouteigenschaften wie "Width " usw. erkannt werden.
  • LayoutUpdated ist ein Ereignis, das ausgelöst wird, wenn sich ein Layoutaspekt des Elements ändert. Dies ist nicht spezifisch für Panels; das Ereignis wird durch 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 jedoch nicht. Beispielsweise kann der interne Inhalt neu angeordnet werden, aber die Größe des Elements hat sich nicht geändert.

Referenz

Konzepte