Strukturen in WPF

In vielen Technologien werden Elemente und Komponenten in einer Baumstruktur organisiert, in denen Entwickler die Objektknoten direkt in der Struktur bearbeiten, um das Rendering oder das Verhalten einer Anwendung zu beeinflussen. Außerdem verwendet Windows Presentation Foundation mehrere Strukturmetaphern, um Beziehungen zwischen Programmelementen festzulegen. Da die WPF-Entwickler meist eine Anwendung im Code erstellen können oder Teile der Anwendung in XAML festlegen, obwohl sie konzeptionell über die Baumstrukturobjektmetapher denken, rufen sie trotzdem eine bestimmte API auf oder verwenden bestimmte Markups, um dies zu tun, anstatt einige allgemeine API-Strukturobjektmanipulationen vorzunehmen, wie Sie sie möglicherweise im XML-DOM verwenden. 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 für das Verstehen des Verhaltens bestimmter WPF-Schlüsselfunktionen hilfreich sind. 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 LogicalTreeHelper und VisualTreeHelpers ein.

Strukturen in WPF

Die umfassendste Struktur 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 festlegen, wird die Baumstruktur basierend darauf erstellt, wie Sie Eigenschaftswerte für Eigenschaften zuweisen, die das Inhaltsmodell für ein bestimmtes Objekt implementieren. In WPF gibt es zwei Möglichkeiten, wie die vollständige Objektstruktur konzipiert wird und an die öffentliche API gemeldet werden kann: Als logische Struktur und als visuelle Struktur. Die Unterschiede zwischen logischer Struktur und visueller Struktur sind nicht immer unbedingt wichtig, aber sie können gelegentlich Probleme mit bestimmten WPF-Subsystemen verursachen und Auswählen im Markup oder im Code beeinträchtigen.

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.

Hinweis

Da die Objektstruktur eher ein Konzept als eine tatsächliche API ist, ist es eine weitere Möglichkeit, sich das Konzept als Objektdiagramm vorzustellen. In der Praxis gibt es Beziehungen zwischen Objekten während der Laufzeit, die die Baumstrukturmetapher aufschlüsseln können. Trotzdem ist die Baumstrukturmetapher, insbesondere bei XAML-definierten Benutzeroberflächen, ausreichend relevant, sodass die meisten WPF-Dokumentationen den Begriff „Objektstruktur“ verwenden werden, wenn auf dieses allgemeine Konzept verwiesen wird.

Die logische Struktur

In WPF fügen Sie Inhalte zu Benutzeroberflächenelementen hinzu, indem Sie Eigenschaften der Objekte festlegen, die diese Elemente unterstützen. 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 zur UIElementCollection hinzu. Ein Codebeispiel finden Sie unter der Vorgehensweise Add an Element Dynamically (Dynamisches Hinzufügen eines Elements).

Wenn Sie in Extensible Application Markup Language (XAML) Listenelemente in einer ListBox oder Steuerelemente bzw. andere Benutzeroberflächenelemente in einem DockPanel platzieren, verwenden Sie auch die Eigenschaften Items und Children, sei es ausdrücklich oder impliziert, 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 das daraus entstehende Objektdiagramm 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 die ListBox vorhanden ist, der ItemCollection durch Parseraufrufe an ItemCollection.Add hinzugefügt. Dieses Beispiel über die Verarbeitung von XAML in einer Objektstruktur ist bisher scheinbar ein Beispiel, bei dem die erstellte Objektstruktur im Grunde die logische Struktur ist.

Die logische Struktur ist jedoch nicht das gesamte Objektdiagramm, das für die Anwendungsbenutzeroberfläche zur Laufzeit vorhanden ist, dies gilt selbst wenn die impliziten XAML-Syntaxelemente nicht berücksichtigt werden. Der Hauptgrund dafür sind die visuellen Objekte und Vorlagen. 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 der logischen Struktur

Die logische Struktur ist vorhanden, damit Inhaltsmodelle ihre potenziellen untergeordneten Objekte leicht durchlaufen können und damit Inhaltsmodelle erweiterbar sind. Darüber hinaus bietet die logische Struktur ein Framework für bestimmte Benachrichtigungen, z.B. wenn alle Objekte in der logischen Struktur geladen werden. Im Grunde ist die logische Struktur eine Annäherung an ein Laufzeit-Objektdiagramm 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-Frameworkebene definiert. Dies bedeutet, dass das relevanteste WPF-Basiselement für Vorgänge der logischen Struktur entweder FrameworkElement oder FrameworkContentElement ist. Wenn Sie die LogicalTreeHelper-API allerdings tatsächlich verwenden, enthält die logische Struktur manchmal Knoten, die nicht FrameworkElement oder FrameworkContentElement sind. 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. Bei den eigentlichen Metadaten, die die Inherits-Eigenschaft enthalten, die die Vererbung von Eigenschaften ermöglichen, handelt es sich um die FrameworkPropertyMetadata-Klasse der WPF-Frameworkebene. 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.

Die visuelle Struktur

Neben dem Konzept der logischen Struktur gibt es auch das Konzept der visuellen Struktur in WPF. Die visuelle Struktur beschreibt die Struktur von visuellen Objekten, wie sie die Visual-Basisklasse darstellt. Wenn Sie eine Vorlage für ein Steuerelement erstellen, werden Sie die visuelle Struktur festlegen oder neu festlegen, die für dieses Steuerelement angewendet wird. Die visuelle Struktur ist auch für Entwickler interessant, die die Kontrolle über Zeichnungen auf niedrigerer Ebene aus Leistungs- und Optimierungsgründen möchten. Eine Offenlegung der visuellen Struktur als Teil der konventionellen WPF-Programmierschnittstellen ist, dass das Ereignis für ein Routingereignis größtenteils entlang der visuellen Struktur steuert, nicht aber entlang der logischen Struktur. Diese Besonderheit des Routingereignisverhaltens ist möglicherweise nicht sofort erkennbar, es sei denn, Sie sind ein Autor 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 (Klassen, die von ContentElement abgeleitet werden) 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 ein ContentElement in einem Inhaltshost gehostet werden, der sowohl ein Visual als auch ein Teilnehmer der logischen Struktur ist. In der Regel ist ein solches Objekt ein FrameworkElement. Sie können konzipieren, dass der Inhaltshost wie ein „Browser“ für den Inhalt ist und wählt, wie der Inhalt innerhalb des Bildschirmbereichs, den der Host steuert, anzuzeigen ist. Wenn der Inhalt gehostet wird, kann der Inhalt zu einem Teilnehmer bestimmter Prozessstrukturen gemacht werden, die normalerweise der visuellen Struktur 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.

Traversierung der Struktur

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 Auflistungseigenschaft verfügbar machen, die Auflistungszugriff, 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 Übersicht über das WPF-Grafikenrendering.

Hinweis

Manchmal ist es notwendig, die visuelle Struktur einer angewendeten Vorlage zu untersuchen. Gehen Sie bei dieser Technik vorsichtig vor. 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 EventRoute darstellt, aber die Methoden dieser Klasse sind normalerweise nur für die interne Verwendung.

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 nicht in der logischen Struktur sind, können auf verschlüsselte Ressourcen 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. Designs selbst können auch auf Systemwerte außerhalb der logischen Struktur des Designs verweisen, wenn die Ressourcenverweise dynamisch sind. Weitere Informationen zu Ressourcenwörterbüchern und der Suchlogik, finden Sie unter XAML-Ressourcen.

Weitere Informationen