Bäume in WPF
In vielen Technologien werden Elemente und Komponenten in einer Baumstruktur organisiert, in der Entwickler die Objektknoten in der Struktur direkt manipulieren, um das Rendering oder Verhalten einer Anwendung zu beeinflussen. Windows Presentation Foundation (WPF) verwendet auch mehrere Baumstrukturmetaphern, um Beziehungen zwischen Programmelementen zu definieren. In den meisten Fällen können WPF-Entwickler eine Anwendung im Code erstellen oder Teile der Anwendung in XAML definieren, während man konzeptuell über die Objektstrukturmetapher nachdenkt. Dabei wird jedoch eine bestimmte API aufgerufen oder ein bestimmtes Markup verwendet, um dies zu erreichen, anstatt eine allgemeine Objektstrukturmanipulations-API zu nutzen, wie es bei XML-DOM der Fall sein könnte. WPF zeigt zwei Hilfsprogrammklassen, die eine Strukturmetapheransicht, LogicalTreeHelper und VisualTreeHelper bereitstellen. Die Begriffe visuelle Struktur und logische Struktur werden auch in der WPF-Dokumentation verwendet, da diese Strukturen hilfreich sind, um das Verhalten bestimmter wichtiger WPF-Features zu verstehen. In diesem Thema wird festgelegt, was die visuelle Struktur und die logische Struktur darstellen, es wird erläutert, wie sich diese Strukturen auf ein allgemeines Objektstrukturkonzept beziehen, und führt mehrere LogicalTreeHelper und VisualTreeHelper ein.
Bäume in WPF
Die vollständigste Baumstruktur in WPF ist die Objektstruktur. Wenn Sie eine Anwendungsseite in XAML festlegen und anschließend XAML laden, wird die Baumstruktur basierend auf den Schachtelungsbeziehungen der Elemente im Markup erstellt. Wenn Sie eine Anwendung oder einen Teil der Anwendung im Code definieren, wird die Baumstruktur basierend darauf erstellt, wie Sie Eigenschaftswerte für Eigenschaften zuweisen, die das Inhaltsmodell für ein gegebenes Objekt implementieren. In WPF gibt es zwei Möglichkeiten, wie die vollständige Objektstruktur konzeptualisiert wird und der öffentlichen API gemeldet werden kann: als logische Struktur und als visuelle Struktur. Die Unterschiede zwischen dem logischen Baum und dem visuellen Baum sind nicht immer wichtig, aber sie können gelegentlich Probleme mit bestimmten WPF-Subsystemen verursachen und sich auf die Auswahlmöglichkeiten im Markup oder Code auswirken.
Obwohl Sie nicht immer die logische Struktur oder die visuelle Struktur direkt bearbeiten, ist das Verstehen der Konzepte, wie die Strukturen interagieren, nützlich, um WPF als eine Technologie zu verstehen. Sich WPF als eine Baumstrukturmetapher vorzustellen, ist auch wichtig, um zu verstehen, wie Eigenschaftsvererbung und Ereignisrouting in WPF funktionieren.
Anmerkung
Da der Objektbaum eher ein Konzept ist als eine tatsächliche API, kann man das Konzept auch als Objektdiagramm betrachten. In der Praxis gibt es Beziehungen zwischen Objekten während der Laufzeit, die die Baumstrukturmetapher aufschlüsseln können. Dennoch ist die Baum-Metapher besonders bei XAML-definierter Benutzeroberfläche so relevant, dass die meisten WPF-Dokumentationen den Begriff Objektbaum verwenden, wenn auf dieses allgemeine Konzept verwiesen wird.
Der logische Baum
In WPF fügen Sie Inhalte zu UI-Elementen hinzu, indem Sie Eigenschaften der Objekte festlegen, die diese Elemente sichern. Beispiel: Sie fügen Elemente zu einem ListBox-Steuerelement hinzu, indem Sie seine Items-Eigenschaft bearbeiten. Dazu platzieren Sie Elemente in der ItemCollection, die den Items-Eigenschaftswert darstellt. Entsprechend bearbeiten Sie zum Hinzufügen von Objekten zu einem DockPanel den Children-Eigenschaftswert. Hier fügen Sie Objekte zu UIElementCollection hinzu. Ein Codebeispiel finden Sie unter So fügen Sie ein Element dynamisch hinzu.
In der Extensible Application Markup Language (XAML), wenn Sie Listenelemente in einem ListBox oder Steuerelemente oder andere UI-Elemente in einem DockPanelplatzieren, verwenden Sie auch die Eigenschaften Items und Children, entweder explizit oder implizit, wie im folgenden Beispiel.
<DockPanel
Name="ParentElement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<!--implicit: <DockPanel.Children>-->
<ListBox DockPanel.Dock="Top">
<!--implicit: <ListBox.Items>-->
<ListBoxItem>
<TextBlock>Dog</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock>Cat</TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock>Fish</TextBlock>
</ListBoxItem>
<!--implicit: </ListBox.Items>-->
</ListBox>
<Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>
<!--implicit: </DockPanel.Children>-->
</DockPanel>
Wenn Sie diesen XAML-Code als XML unter einem Dokumentobjektmodell verarbeiten würden und die auskommentierten Tags als implizit eingeschlossen hätten (was zulässig gewesen wäre), hätte die entstandene XML-DOM-Struktur Elemente für <ListBox.Items>
und für die anderen impliziten Elemente eingeschlossen. XAML verarbeitet jedoch nicht auf diese Weise, und wenn Sie das Markup lesen und in Objekte schreiben, enthält der daraus entstehende Objektgraph nicht wirklich ListBox.Items
. Es verfügt allerdings über eine ListBox-Eigenschaft namens Items
, die eine ItemCollection enthält. Diese ItemCollection ist initialisiert, aber leer, wenn ListBox-XAML verarbeitet wird. Anschließend wird jedes untergeordnete Objektelement, das als Inhalt für ListBox vorhanden ist, der ItemCollection durch Parseraufrufe an ItemCollection.Add
hinzugefügt. Dieses Beispiel für die Verarbeitung von XAML in einer Objektstruktur ist bisher scheinbar ein Beispiel, in dem die erstellte Objektstruktur im Grunde die logische Struktur ist.
Der logische Baum ist jedoch nicht das gesamte Objektdiagramm, das zur Laufzeit für Ihre Anwendungsoberfläche vorhanden ist, selbst wenn die impliziten XAML-Syntaxelemente herausgerechnet werden. Der Hauptgrund dafür sind Visuals und Templates. Betrachten Sie beispielsweise Button. Die logische Struktur meldet das Button-Objekt und auch seine Zeichenfolge Content
. Es gibt jedoch noch mehr zu dieser Schaltfläche in der Laufzeit-Objektstruktur. Insbesondere wird die Schaltfläche nur deshalb auf diese Art auf dem Bildschirm angezeigt, weil eine bestimmte Button-Steuerelementvorlage angewendet wurde. Die visuellen Objekte, die aus einer angewendeten Vorlage stammen (z. B. das dunkelgraue vorlagendefinierte Border-Element auf der visuellen Schaltfläche), werden nicht in der logischen Struktur gemeldet, auch wenn Sie während der Laufzeit einen Blick auf die logische Struktur werfen (z. B. der Umgang mit einem Eingabeereignis in der sichtbaren Benutzeroberfläche und anschließend das Lesen der logischen Struktur). Sie müssten stattdessen die visuelle Struktur untersuchen, um die visuellen Vorlagen zu suchen.
Weitere Informationen dazu, wie die XAML-Syntax das erstellte Objektdiagramm sowie die implizite Syntax in XAML zuordnet, finden Sie unter Ausführliche Erläuterung der XAML-Syntax oder XAML in WPF.
Der Zweck des logischen Baums
Die logische Struktur ist vorhanden, damit Inhaltsmodelle ihre potenziellen untergeordneten Objekte leicht durchlaufen können und damit Inhaltsmodelle erweiterbar sind. Außerdem stellt die logische Struktur ein Framework für bestimmte Benachrichtigungen bereit, z. B. wenn alle Objekte in der logischen Struktur geladen werden. Im Grunde ist die logische Struktur eine Annäherung an einen Laufzeit-Objektgraph auf der Frameworkebene, das visuelle Elemente ausschließt, aber für viele Abfragevorgänge für Ihre eigene Laufzeit-Anwendungskomposition ausreichend ist.
Darüber hinaus werden sowohl statische als auch dynamische Ressourcenverweise durch Durchsuchen der logischen Struktur für Resources-Auflistungen am anfänglichen Anforderungsobjekt aufgelöst und fahren dann mit ihrer Suche in der Struktur nach oben fort und prüfen jedes FrameworkElement (oder FrameworkContentElement) auf einen weiteren Resources
-Wert mit ResourceDictionary, das möglicherweise den gesuchten Schlüssel enthält. Die logische Struktur wird für die Ressourcensuche verwendet, wenn sowohl die logische Struktur als auch die visuelle Struktur vorhanden sind. Weitere Informationen zu Ressourcenwörterbüchern und der Suche finden Sie unter XAML-Ressourcen.
Zusammensetzung der logischen Struktur
Die logische Struktur wird auf der WPF-Framework-Ebene definiert, was bedeutet, dass das WPF-Basiselement, das für logische Strukturvorgänge am relevantesten ist, entweder FrameworkElement oder FrameworkContentElementist. Wie Sie jedoch sehen können, wenn Sie die LogicalTreeHelper-API tatsächlich verwenden, enthält der logische Baum manchmal Knoten, die weder FrameworkElement noch FrameworkContentElementsind. Die logische Struktur meldet z. B. den Text-Wert eines TextBlock-Elements, bei dem es sich um eine Zeichenfolge handelt.
Überschreiben der logischen Struktur
Erfahrene Steuerelementautoren können die logische Struktur überschreiben, indem Sie mehrere APIs überschreiben, die festlegen, wie ein allgemeines Objekt- oder Inhaltsmodell Objekte innerhalb der logischen Struktur hinzufügt oder entfernt. Ein Beispiel zum Überschreiben der logischen Struktur finden Sie unter Überschreiben der logischen Struktur.
Vererbung von Eigenschaftswerten
Die Vererbung von Eigenschaftswerten funktioniert mithilfe einer Hybridstruktur. Die tatsächlichen Metadaten, die die Inherits-Eigenschaft enthalten, welche die Eigenschaftsvererbung ermöglicht, sind die Klasse FrameworkPropertyMetadata der WPF-Framework-Ebene. Aus diesem Grund müssen sowohl das übergeordnete Element, das den ursprünglichen Wert enthält, als auch das untergeordnete Objekt, das diesen Wert erbt, FrameworkElement oder FrameworkContentElement sein, außerdem müssen sie beide Teil einer logischen Struktur sein. Allerdings kann für vorhandene WPF-Eigenschaften, die die Vererbung von Eigenschaften unterstützen, die Vererbung von Eigenschaftswerten durch ein beteiligtes Objekt aufrechterhalten werden, das nicht in der logischen Struktur ist. Dies ist vor allem relevant, wenn Vorlagenelemente alle geerbten Eigenschaftswerte verwenden, die entweder auf die Instanz festgelegt wurden, die als Vorlage verwendet wird, oder auf noch höheren Ebenen der Seitenebenen-Zusammensetzung und aus diesem Grund höher in der logischen Struktur sind. Damit die Vererbung von Eigenschaftswerten über eine solche Grenze hinweg konsistent funktioniert, muss die erbende Eigenschaft als angefügte Eigenschaft registriert werden, und Sie sollten dieses Muster befolgen, wenn Sie beabsichtigen, eine benutzerdefinierte Abhängigkeitseigenschaft mit Eigenschaftenvererbungsverhalten festzulegen. Die genaue Struktur, die für die Vererbung von Eigenschaften verwendet wurde, kann nicht vollständig von einer Hilfsprogrammklassen-Dienstmethode vorhergesehen werden, dies gilt selbst während der Laufzeit. Weitere Informationen finden Sie unter Vererbung von Eigenschaftswerten.
Visueller Baum
Neben dem Konzept der logischen Struktur gibt es auch das Konzept der visuellen Struktur in WPF. Der visuelle Baum beschreibt die Struktur visueller Objekte, wie durch die Visual-Basisklasse dargestellt. Wenn Sie eine Vorlage für ein Steuerelement schreiben, definieren oder redefinieren Sie den visuellen Baum, der für dieses Steuerelement gilt. Der visuelle Baum ist auch für Entwickler interessant, die aus Leistungs- und Optimierungsgründen eine niedrigere Ebene der Kontrolle über das Zeichnen wünschen. Eine Darstellung des visuellen Baums als Teil der herkömmlichen WPF-Anwendungsprogrammierung besteht darin, dass Ereignisrouten für ein geroutetes Ereignis hauptsächlich entlang des visuellen Baums, nicht des logischen Baums, verlaufen. Diese Besonderheit des Routingereignisverhaltens ist möglicherweise nicht sofort erkennbar, es sei denn, Sie sind Erstellender des Steuerelements. Routingereignisse über die visuelle Struktur ermöglichen Steuerelemente, die die Komposition auf der visuellen Ebene implementieren, um Ereignisse zu bearbeiten oder Ereignissetter zu erstellen.
Strukturen, Inhaltselemente und Inhaltshosts
Inhaltselemente (Von ContentElementabgeleitete Klassen) sind nicht Teil der visuellen Struktur; sie erben nicht von Visual und haben keine visuelle Darstellung. Um in einer Benutzeroberfläche überhaupt angezeigt zu werden, muss ContentElement in einem Inhaltshost gehostet werden, der sowohl Visual als auch ein Teilnehmer der logischen Struktur ist. In der Regel ist ein solches Objekt ein FrameworkElement. Sie können sich vorstellen, dass der Inhaltshost etwas wie ein "Browser" für den Inhalt ist und auswählt, wie dieser Inhalt im Bildschirmbereich angezeigt wird, den der Host steuert. Wenn der Inhalt gehostet wird, kann er an bestimmten Baumprozessen teilnehmen, die normalerweise dem visuellen Baum zugeordnet sind. In der Regel enthält die Hostklasse FrameworkElement den Implementierungscode, der ein gehostetes ContentElement für die Ereignisroute über Unterknoten der logischen Inhaltsstruktur hinzufügt, obwohl der gehostete Inhalt kein Teil der echten visuellen Struktur ist. Dies ist erforderlich, damit ein ContentElement von einem Routingereignis stammen kann, das alle Elemente außer sich selbst steuert.
Strukturdurchlauf
Die LogicalTreeHelper-Klasse stellt die Methoden GetChildren, GetParent und FindLogicalNode für die logische Strukturverzweigung bereit. In den meisten Fällen sollte Sie nicht die logische Struktur von vorhandenen Steuerelementen durchlaufen müssen, da diese Steuerelemente fast immer ihre logisch untergeordneten Elemente als dedizierte Sammlungseigenschaft verfügbar machen, die Sammlungszugriff, wie z. B. Add
, einen Indexer und so weiter, unterstützt. Strukturverzweigung ist ein Szenario, dass vor allem von Autoren von Steuerelementen verwendet wird, die sich nicht von geplanten Steuerelementmustern wie ItemsControl oder Panel ableiten, bei denen Auflistungseigenschaften bereits festgelegt sind, und die ihre eigene Unterstützung für Auflistungseigenschaften bereitstellen möchten.
Die visuelle Struktur unterstützt auch eine Hilfsprogrammklasse für die Verzweigung der visuellen Struktur, VisualTreeHelper. Die visuelle Struktur ist nicht offengelegt, wie es mit steuerelementspezifischen Eigenschaften praktisch möglich wäre, sodass die VisualTreeHelper-Klasse die empfohlene Methode ist, um die visuelle Struktur zu durchlaufen, wenn dies für Ihr Programmierungsszenario erforderlich ist. Weitere Informationen finden Sie unter WPF Graphics Rendering Overview.
Anmerkung
Manchmal ist es notwendig, den visuellen Baum einer angewendeten Vorlage zu untersuchen. Bei verwendung dieser Technik sollten Sie vorsichtig sein. Auch wenn Sie eine visuelle Struktur für ein Steuerelement durchlaufen, wobei Sie die Vorlage festlegen, können Consumer Ihres Steuerelements immer die Vorlage ändern, indem sie die Template-Eigenschaft für Instanzen festlegen, und sogar der Endbenutzer kann die angewendete Vorlage durch Ändern des Systemdesigns beeinflussen.
Routen für Routingereignisse als „Struktur“
Wie bereits erwähnt, durchläuft die Route aller angegebenen Routingereignisse entlang eines einzelnen und vordefinierten Pfads einer Struktur, die eine Mischung aus den Darstellungen visueller und logischer Strukturen ist. Die Ereignisroute kann innerhalb der Struktur nach oben oder nach unten passieren, je nachdem, ob es ein Tunnel- oder Bubbling-Routingereignis ist. Das Konzept der Ereignisroute hat keine direkt unterstützende Hilfsprogrammklasse, die verwendet werden kann, um die Ereignisroute unabhängig vom Auslösen eines Ereignisses, das tatsächlich weiterleitet, zu „durchlaufen“. Es gibt eine Klasse, die die Route, EventRoutedarstellt, aber die Methoden dieser Klasse sind in der Regel nur für die interne Verwendung bestimmt.
Ressourcenwörterbücher und Strukturen
Wörterbuchressourcensuche für alle Resources
, die auf einer Seite festgelegt sind, durchlaufen im Grunde die logische Struktur. Objekte, die sich nicht in der logischen Struktur befinden, können auf Schlüsselressourcen verweisen, aber die Ressourcensuchsequenz beginnt an dem Punkt, an dem das Objekt mit der logischen Struktur verbunden ist. In WPF können nur logische Strukturknoten über eine Resources
-Eigenschaft verfügen, die ein ResourceDictionary enthalten, aus diesem Grund gibt es keinen Vorteil der Verzweigung der visuellen Struktur auf der Suche nach verschlüsselten Ressourcen aus einem ResourceDictionary.
Die Ressourcensuche kann jedoch auch über die unmittelbare logische Struktur hinaus erweitert werden. Bei Anwendungsmarkups kann die Ressourcensuche auf Anwendungsebene von Ressourcenwörterbüchern weitergeführt werden, und anschließend bei der Designunterstützung und den Systemwerten fortgesetzt werden, die als statische Eigenschaften oder Schlüssel referenziert werden. Themen selbst können auch auf Systemwerte außerhalb der logischen Themenstruktur verweisen, wenn die Ressourcenverweise dynamisch sind. Weitere Informationen zu Ressourcenwörterbüchern und der Logik des Nachschlagens finden Sie unter XAML-Ressourcen.
Weitere Informationen
.NET Desktop feedback