Grundlagen zu XAML-Knotenstreamstrukturen und -konzepten

Die in .NET Framework-XAML-Diensten implementierten XAML-Reader und XAML-Writer basieren auf dem Entwurfskonzept eines XAML-Knotenstreams. Der XAML-Knotenstream ist eine Konzeptualisierung eines Satzes von XAML-Knoten. In dieser Konzeptualisierung arbeitet ein XAML-Prozessor die Struktur der Knotenbeziehungen im XAML einzeln ab. Dabei ist immer nur ein aktueller Datensatz oder eine aktuelle Position in einem geöffneten XAML-Knotenstream vorhanden, und viele Aspekte der APIs melden nur die von dieser Position verfügbaren Informationen. Der aktuelle Knoten in einem XAML-Knotenstream kann als Objekt, Member oder Wert beschrieben werden. Indem Sie XAML als einen XAML-Knotenstream behandeln, können XAML-Reader mit XAML-Writern kommunizieren und ein Programm aktivieren, um die Inhalte eines XAML-Knotenstreams während eines Ladepfad- oder Speicherpfadvorgangs, an dem XAML beteiligt ist, anzuzeigen, mit diesen zu interagieren oder sie zu verändern. Der API-Entwurf von XAML-Readern und -Writern und das Konzept des XAML-Knotenstreams ähneln früheren verwandten Reader- und Writerentwürfen und -konzepten, z. B. dem XML Document Object Model (DOM) und den XmlReader- und XmlWriter-Klassen. In diesem Thema werden XAML-Knotenstreamkonzepte erläutert, und es wird beschrieben, wie Sie Routinen schreiben können, die mit XAML-Darstellungen auf XAML-Knotenebene interagieren.

Dieses Thema enthält folgende Abschnitte.

  • Laden von XAML in einen XAML-Reader
  • Eine grundlegende Leseknotenschleife
  • Arbeiten mit dem aktuellen Knoten
  • Durchlaufen und Eingeben von Objektknoten
  • Wertkonverter und der XAML-Knotenstream
  • Durch XAML- und XML-Sprache definierte Member im XAML-Knotenstream
  • Knotenreihenfolge
  • Verwandte Abschnitte

Laden von XAML in einen XAML-Reader

Die XamlReader-Basisklasse deklariert kein bestimmtes Verfahren zum Laden der ursprünglichen XAML in einen XAML-Reader. Stattdessen deklariert und implementiert eine abgeleitete Klasse die Ladetechnik, einschließlich der allgemeinen Eigenschaften und Einschränkungen der Eingabequelle für XAML. Ein XamlObjectReader liest z. B. ein Objektdiagramm beginnend mit der Eingabequelle eines einzelnen Objekts, das den Stamm oder die Basis darstellt. Anschließend erzeugt der XamlObjectReader einen XAML-Knotenstream aus dem Objektdiagramm.

Die bekannteste von .NET Framework-XAML-Diensten definierte XamlReader-Unterklasse ist XamlXmlReader. Der XamlXmlReader lädt das anfängliche XAML, indem eine Textdatei direkt über einen Stream oder Dateipfad oder indirekt über eine zugehörige Readerklasse wie TextReader geladen wird. Der XamlReader enthält somit die gesamte XAML-Eingabequelle, nachdem diese geladen wurde. Die XamlReader-Basis-API ist jedoch so aufgebaut, dass der Reader mit einem einzelnen Knoten der XAML interagiert. Beim erstmaligen Laden ist der erste gefundene einzelne Knoten der Stamm des XAML und das zugehörige Startobjekt.

XAML-Knotenstreamkonzept

Wenn Sie generell besser mit einem DOM-, strukturmetapher- oder abfragebasierten Ansatz für den Zugriff auf XML-basierte Technologien vertraut sind, ist es hilfreich, sich einen XAML-Knotenstream wie im Folgenden beschrieben vorzustellen. Stellen Sie sich vor, dass das geladene XAML ein DOM oder eine Struktur ist, in dem bzw. der jeder mögliche Knoten vollständig erweitert und anschließend linear dargestellt wird. Wenn Sie die Knoten durchlaufen, begegnen Ihnen möglicherweise Ebenen, die bei einem DOM relevant wären, vom XAML-Knotenstream aber nicht explizit verfolgt werden, weil diese Ebenenkonzepte für einen Knotenstream nicht relevant sind. Der Knotenstream hat eine "aktuelle" Position. Sofern Sie andere Teile des Streams jedoch nicht selbst als Verweise gespeichert haben, sind alle Aspekte des Knotenstreams mit Ausnahme der aktuellen Knotenposition nicht sichtbar.

Das XAML-Knotenstreamkonzept bietet den wichtigen Vorteil, dass Sie sicher sein können, dass die gesamte XAML-Darstellung verarbeitet wurde, wenn Sie den ganzen Knotenstream durchlaufen. Sie müssen sich keine Gedanken machen, dass bei einer Abfrage, einem DOM-Vorgang oder einem anderen nicht linearen Ansatz der Informationsverarbeitung ein Teil der vollständigen XAML-Darstellung übersehen wurde. Aus diesem Grund ist die Darstellung eines XAML-Knotenstreams sowohl für die Verbindung von XAML-Readern und XAML-Writern als auch die Bereitstellung eines Systems, in dem Sie Ihren eigenen, zwischen den Lese- und Schreibphasen eines XAML-Verarbeitungsvorgangs eingesetzten Prozess einfügen können, ideal geeignet. In vielen Fällen wird die Reihenfolge von Knoten im XAML-Knotenstream gegenüber der möglichen Reihenfolge im Quelltext, in der Binärdatei oder im Objektdiagramm bewusst von XAML-Readern optimiert oder neu geordnet. Durch dieses Verhalten wird eine XAML-Verarbeitungsarchitektur erzwungen, in der XAML-Writer nie im Knotenstream zurückgehen müssen. Im Idealfall sollten alle XAML-Schreibvorgänge in der Lage sein, basierend auf dem Schemakontext und der aktuellen Position des Knotenstreams zu arbeiten.

Eine grundlegende Leseknotenschleife

Eine grundlegende Lesenknotenschleife zum Untersuchen eines XAML-Knotenstreams besteht aus den folgenden Konzepten. Bei den in diesem Thema erläuterten Knotenschleifen wird davon ausgegangen, dass Sie eine textbasierte, lesbare XAML-Datei mit XamlXmlReader lesen. Die Links in diesem Abschnitt verweisen auf die von XamlXmlReader implementierte XAML-Knotenschleifen-API.

  • Stellen Sie sicher, dass Sie sich nicht am Ende des XAML-Knotenstreams befinden (überprüfen Sie IsEof, oder verwenden Sie den Read()-Rückgabewert). Wenn Sie sich am Ende des Streams befinden, gibt es keinen aktuellen Knoten, und Sie sollten den Stream beenden.

  • Überprüfen Sie, welchen Knotentyp der XAML-Knotenstream gerade bereitstellt, indem Sie NodeType aufrufen.

  • Wenn Sie über einen zugehörigen direkt verbundenen XAML-Objektwriter verfügen, rufen Sie an dieser Stelle im Allgemeinen WriteNode auf.

  • Verwenden Sie abhängig davon, welcher XamlNodeType als aktueller Knoten oder aktueller Datensatz gemeldet wird, einen der folgenden Aufrufe, um Informationen zum Knoteninhalt zu erhalten:

    • Lautet der NodeType StartMember oder EndMember, rufen Sie Member auf, um XamlMember-Informationen zu einem Member zu erhalten. Da der Member eine XamlDirective sein könnte, ist er nicht zwingend ein konventioneller Member mit definiertem Typ des vorherigen Objekts. Ein auf ein Objekt angewendeter x:Name wird z. B. als XAML-Member angezeigt, bei dem IsDirective "true" und der Name des Members Name ist und andere Eigenschaften angeben, dass diese Direktive im XAML-Namespace der XAML-Sprache enthalten ist.

    • Lautet der NodeType StartObject oder EndObject, rufen Sie Type auf, um XamlType-Informationen zu einem Objekt zu erhalten.

    • Lautet der NodeType Value, rufen Sie Value auf. Ein Knoten ist nur ein Wert, wenn er der einfachste Ausdruck eines Werts für einen Member oder der Initialisierungstext für ein Objekt ist (dabei ist jedoch das weiter unten in diesem Thema beschriebene Typkonvertierungsverhalten zu beachten).

    • Lautet der NodeType NamespaceDeclaration, rufen Sie Namespace auf, um Namespaceinformationen für einen Namespaceknoten zu erhalten.

  • Rufen Sie Read auf, um den XAML-Reader auf den nächsten Knoten im XAML-Knotenstream zu setzen, und wiederholen Sie die Schritte.

Der von .NET Framework-XAML-Diensten bereitgestellte XAML-Knotenstream stellt immer einen vollständigen, tiefen Durchlauf aller möglichen Knoten bereit. Typische Flusssteuerungstechniken für eine XAML-Knotenschleife umfassen die Definition eines Texts in while (reader.Read()) und das Aktivieren von NodeType an jedem Knotenpunkt in der Knotenschleife.

Wenn sich der Knotenstream am Dateiende befindet, ist der aktuelle Knoten NULL.

Das folgende Beispiel zeigt die einfachste Schleife mit einem Reader und Writer.

XamlXmlReader xxr = new XamlXmlReader(new StringReader(xamlStringToLoad));
//where xamlStringToLoad is a string of well formed XAML
XamlObjectWriter xow = new XamlObjectWriter(xxr.SchemaContext);
while (xxr.Read()) {
  xow.WriteNode(xxr);
}

In diesem grundlegenden Beispiel für eine Ladepfad-XAML-Knotenschleife werden XAML-Reader und XAML-Writer verbunden. Dies entspricht der Verwendung von XamlServices.Parse. Aber diese grundlegende Struktur wird anschließend dem Lese- oder Schreibeszenario entsprechend erweitert. Folgende sind einige mögliche Szenarien:

  • Vorhandener Schalter auf NodeType. Ausführen unterschiedlicher Aktionen, abhängig vom gelesenen Knotentyp.

  • In keinem Fall wird WriteNode aufgerufen. WriteNode wird nur in einigen NodeType-Fällen aufgerufen.

  • Innerhalb der Logik für einen bestimmten Knotentyp werden die Einzelheiten des Knotens analysiert und bearbeitet. Zum Beispiel könnten nur Objekte geschrieben werden, die von einem bestimmten XAML-Namespace stammen und anschließend alle Objekte zurückgestellt oder abgelegt werden, die nicht von einem XAML-Namespace stammen. Oder beliebige XAML-Direktiven, die das XAML-System nicht als Teil der Memberverarbeitung unterstützt, könnten abgelegt oder auf eine andere Art erneut verarbeitet werden.

  • Ein benutzerdefiniertes XamlObjectWriter-Element wird definiert, von dem Write*-Methoden überschrieben werden und möglicherweise eine Typzuordnung ausgeführt wird, die den XAML-Schemakontext umgeht.

  • Erstellen Sie den XamlXmlReader mit einem nicht standardmäßigen XAML-Schemakontext, sodass benutzerdefinierte Unterschiede im XAML-Verhalten sowohl vom Reader als auch vom Writer verwendet werden.

Zugreifen auf XAML jenseits des Knotenschleifenkonzepts

Es gibt andere Möglichkeiten als eine XAML-Knotenschleife, um mit einer XAML-Darstellung zu arbeiten. Es könnte z. B. einen XAML-Reader geben, der einen indizierten Knoten lesen kann, oder insbesondere direkt über x:Name, über x:Uid oder über andere Bezeichner auf Knoten zugreift. .NET Framework-XAML-Dienste stellen keine vollständige Implementierung bereit, sondern durch Dienste und Unterstützungstypen ein vorgeschlagenes Muster. Weitere Informationen finden Sie unter IXamlIndexingReader und XamlNodeList.

TippTipp

Microsoft bietet auch eine Out-of-Band-Version an, die als Microsoft XAML Toolkit bezeichnet wird.Diese Out-of-Band-Version befindet sich noch in den Vorabveröffentlichungsphasen.Wenn Sie jedoch bereit sind, mit Vorabveröffentlichungskomponenten zu arbeiten, finden Sie im Microsoft XAML Toolkit mehrere interessante Ressourcen für XAML-Tools und die statische Analyse von XAML.Das Microsoft XAML Toolkit bietet Unterstützung für eine XAML-DOM-API zur FxCop-Analyse und einen XAML-Schemakontext für Silverlight.Weitere Informationen finden Sie unter Microsoft XAML Toolkit.

Arbeiten mit dem aktuellen Knoten

Bei den meisten Szenarien mit einer XAML-Knotenschleife werden die Knoten nicht nur gelesen. In den meisten Szenarien werden aktuelle Knoten verarbeitet, und jeder Knoten wird einzeln an eine Implementierung von XamlWriter übergeben.

Im typischen Ladepfadszenario erzeugt ein XamlXmlReader einen XAML-Knotenstream. Die XAML-Knoten werden entsprechend der Logik und dem XAML-Schemakontext verarbeitet und an einen XamlObjectWriter übergeben. Anschließend integrieren Sie das resultierende Objektdiagramm in die Anwendung oder das Framework.

In einem typischen Speicherpfadszenario liest ein XamlObjectReader das Objektdiagramm, einzelne XAML-Knoten werden verarbeitet, und ein XamlXmlWriter gibt das serialisierte Ergebnis als XAML-Textdatei aus. Der wichtigste Aspekt dabei ist, dass bei beiden Pfaden und Szenarien jeweils mit genau einem XAML-Knoten gearbeitet wird und die XAML-Knoten für die standardisierte Behandlung verfügbar sind, die im XAML-Typsystem und in der .NET Framework-XAML-Dienste-API definiert ist.

Frames und Bereich

Eine XAML-Knotenschleife durchläuft einen XAML-Knotenstream linear. Der Knotenstream durchläuft Objekte, Member, die andere Objekte enthalten usw. Oft ist es hilfreich, den Bereich innerhalb des XAML-Knotenstreams durch Implementieren eines Frame- und Stapelkonzepts nachzuverfolgen. Dies gilt besonders, wenn Sie den Knotenstream aktiv anpassen, währen Sie sich darin befinden. Die Frame- und Stapelunterstützung, die Sie als Teil der Knotenschleifenlogik implementieren, könnte die Bereiche StartObject (oder GetObject) und EndObject zählen, während Sie eine XAML-Knotenstruktur – bei Betrachtung aus der DOM-Perspektive – nach unten durchlaufen.

Durchlaufen und Eingeben von Objektknoten

Der erste von einem XAML-Reader geöffnete Knoten in einem Knotenstream ist der Startobjektknoten des Stammobjekts. Definitionsgemäß ist dieses Objekt immer ein einzelner Objektknoten ohne Peers. In einem realen XAML-Beispiel wird das Stammobjekt so definiert, dass es über eine oder mehrere Eigenschaften verfügt, die mehrere Objekte enthalten, und diese Eigenschaften verfügen über Memberknoten. Die Memberknoten verfügen dann über mindestens einen Objektknoten oder könnten stattdessen auch in einem Wertknoten beendet werden. Das Stammobjekt definiert normalerweise XAML-Namensbereiche, die syntaktisch als Attribute im XAML-Textmarkup zugewiesen werden, aber einem Namescope-Knotentyp in der XAML-Knotenstreamdarstellung entsprechen.

Beachten Sie das folgende XAML-Beispiel (dies ist beliebiges von in .NET Framework vorhandenen Typen nicht unterstütztes XAML). Angenommen, in diesem Objektmodell gilt Folgendes: FavorCollection ist List<T> von Favor, Balloon und NoiseMaker können Favor zugewiesen werden, die Balloon.Color-Eigenschaft wird von einem Color-Objekt unterstützt (ähnlich der WPF-Definition von Farben als bekannte Farbnamen), und Color unterstützt einen Typkonverter für die Attributsyntax.

XAML-Markup

Sich ergebender XAML-Knotenstream

<Party

Namespace-Knoten für Party

xmlns="PartyXamlNamespace">

StartObject-Knoten für Party

  <Party.Favors>

StartMember-Knoten für Party.Favors

StartObject-Knoten für implizites FavorCollection-Element

StartMember-Knoten für implizite FavorCollection-Elementeigenschaft

    <Balloon

StartObject-Knoten für Balloon

      Color="Red"

StartMember-Knoten für Color

  Value-Knoten für die "Red"-Attributwertzeichenfolge.

EndMember für Color.

      HasHelium="True"

StartMember-Knoten für HasHelium.

  Value-Knoten für die "True"-Attributwertzeichenfolge.

EndMember für HasHelium.

    >

EndObject für Balloon.

    <NoiseMaker>Loudest</NoiseMaker>

StartObject-Knoten für NoiseMaker.

  StartMember-Knoten für _Initialization

    Value-Knoten für die "Loudest"-Initialisierungswertzeichenfolge.

  EndMember-Knoten für _Initialization

EndObject für NoiseMaker

EndMember-Knoten für implizite FavorCollection-Elementeigenschaft

EndObject-Knoten für implizites FavorCollection-Element

  </Party.Favors>

EndMember für Favors

</Party>

EndObject für Party

Im XAML-Knotenstream wird das folgende Verhalten verwendet:

  • Wenn ein Namespace-Knoten vorhanden ist, wird er dem Stream unmittelbar vor dem StartObject hinzugefügt, von dem der XAML-Namespace mit xmlns deklariert wurde. Werfen Sie erneut einen Blick auf die vorherige Tabelle mit dem XAML und dem Beispielknotenstream. Beachten Sie, dass die StartObject- und Namespace-Knoten entgegen ihren Deklarationspositionen im Markup transponiert zu sein scheinen. Dies ist repräsentativ für das Verhalten, bei dem die Namespaceknoten immer vor dem Knoten angezeigt werden, für den sie im Knotenstream gelten. Dieser Entwurf begründet sich dadurch, dass die Namespaceinformationen für Objektwriter unerlässlich sind und bekannt sein müssen, bevor der Objektwriter versucht, die Typzuordnung auszuführen oder das Objekt anderweitig zu verarbeiten. Indem die XAML-Namespaceinformationen im Stream vor ihrem Anwendungsbereich platziert werden, kann der Knotenstream leichter immer in der dargestellten Reihenfolge verarbeitet werden.

  • Wie bereits dargelegt, ist es mindestens ein Namespace-Knoten, der in den meisten realen Markupfällen zuerst gelesen wird, sobald Knoten vom Start und nicht vom StartObject-Element des Stamms durchlaufen werden.

  • Einem StartObject-Knoten kann ein StartMember-, ein Value- oder ein EndObject-Element direkt folgen. Ihm folgt nie sofort ein weiteres StartObject.

  • Einem StartMember-Element kann ein StartObject-, ein Value- oder ein EndMember-Element direkt folgen. Bei Membern, bei denen der Wert aus einem vorhandenen Wert des übergeordnetes Objekts und nicht aus einem StartObject stammt, das einen neuen Wert instanziieren würde, kann ihm GetObject folgen. Ihm kann auch ein Namespace-Knoten folgen, der für ein späteres StartObject gilt. Ihm folgt nie sofort ein weiterer StartMember.

  • Ein Value-Knoten stellt den Wert selbst dar. Es gibt kein EndValue-Element. Ihm kann nur ein EndMember folgen.

    • Der XAML-Initialisierungstext des Objekts, wie er von der Konstruktion verwendet werden könnte, führt nicht zu einer Object-Value-Struktur. Stattdessen wird ein dedizierter Memberknoten für einen Member mit dem Namen _Initialization erstellt. Und dieser Memberknoten enthält die Initialisierungswertzeichenfolge. Falls vorhanden, ist _Initialization immer der erste StartMember. _Initialization wird in einigen XAML-Dienst-Darstellungen möglicherweise mit dem XAML-Sprachen-XAML-Namescope qualifiziert, um klarzustellen, dass _Initialization keine definierte Eigenschaft in unterstützenden Typen ist.

    • Eine Member-Wert-Kombination stellt eine Attributeinstellung des Werts dar. An der Verarbeitung dieses Werts kann ein Wertkonverter beteiligt sein, und der Wert ist eine einfache Zeichenfolge. Das wird erst jedoch ausgewertet, wenn ein XAML-Objektwriter diesen Knotenstream verarbeitet. Der XAML-Objektwriter besitzt den notwendigen XAML-Schemakontext, die Typsystemzuordnung und andere Unterstützung, die für Wertkonvertierungen benötigt wird.

  • Einem EndMember-Knoten kann ein StartMember-Knoten für einen nachfolgenden Member oder ein EndObject-Knoten für den Memberbesitzer folgen.

  • Einem EndObject-Knoten kann ein EndMember-Knoten folgen. In Fällen, in denen Objekte Peers in den Elementen einer Auflistung sind, kann ihm auch ein StartObject-Knoten folgen. Oder Ihm folgt ein Namespace-Knoten, der für ein späteres StartObject gilt.

    • Für den eindeutigen Fall, dass ein gesamter Knotenstream geschlossen wird, folgt dem EndObject-Element des Stamms kein weiteres Element. Der Reader befindet sich jetzt am Dateiende, und Read gibt false zurück.

Wertkonverter und der XAML-Knotenstream

Ein Wertkonverter ist ein allgemeiner Begriff für eine Markuperweiterung, einen Typkonverter (einschließlich Wertserialisierungsprogrammen) oder eine andere dedizierte Klasse, die als Wertkonverter durch das XAML-Typsystem gemeldet wird. Im XAML-Knotenstream werden Typkonverter- und Markuperweiterungsverwendungen sehr unterschiedlich dargestellt.

Typkonverter im XAML-Knotenstream

Ein festgelegtes Attribut, das schließlich zur Verwendung eines Typkonverters führt, wird im XAML-Knotenstream als Wert eines Members gemeldet. Der XAML-Knotenstream erzeugt kein Typkonverterinstanzobjekt und übergibt den Wert auch nicht an das Objekt. Zur Verwendung einer Konvertierungsimplementierung des Typkonverters muss der XAML-Schemakontext aufgerufen und zur Typzuordnung verwendet werden. Selbst die Bestimmung, welche Typkonverterklasse verwendet werden soll, um den Wert zu verarbeiten, erfordert indirekt den XAML-Schemakontext. Wenn Sie den XAML-Standardschemakontext verwenden, sind diese Informationen im XAML-Typsystem verfügbar. Falls Sie die Informationen zur Typkonverterklasse auf der XAML-Knotenstreamebene vor der Verbindung mit einem XAML-Writer benötigen, können Sie sie aus den XamlMember-Informationen des festgelegten Members abrufen. Andernfalls sollte die Typkonvertereingabe im XAML-Knotenstream als einfacher Wert beibehalten werden, bis die übrigen Vorgänge, die das Typzuordnungssystem und den XAML-Schemakontext erfordern (z. B. die Objekterstellung durch einen XAML-Objektwriter), ausgeführt wurden.

Werfen Sie z. B. einen Blick auf die folgende Klassendefinitionsgliederung und die entsprechende XAML-Verwendung:

    public class BoardSizeConverter : TypeConverter {
      //converts from string to an int[2] by splitting on an "x" char
    }
    public class GameBoard {
      [TypeConverter(typeof(BoardSizeConverter))]
      public int[] BoardSize; //2x2 array, initialization not shown
    }
    <GameBoard BoardSize="8x8"/>

Eine Textdarstellung des XAML-Knotenstreams für diese Verwendung könnte folgendermaßen aussehen:

Ein StartObject-Element mit XamlType, das GameBoard darstellt.

Ein StartMember-Element mit XamlMember, das BoardSize darstellt.

Value-Knoten mit Textzeichenfolge "8x8"

EndMember stimmt mit BoardSize überein.

EndObject stimmt mit GameBoard überein.

Beachten Sie, dass es keine Typkonverterinstanz in diesem Knotenstream gibt. Sie können Typkonverterinformationen jedoch abrufen, indem Sie XamlMember.TypeConverter für den XamlMember für BoardSize aufrufen. Wenn ein gültiger XAML-Schemakontext vorhanden ist, können Sie die Konvertermethoden auch aufrufen, indem Sie eine Instanz von ConverterInstance abrufen.

Markuperweiterungen im XAML-Knotenstream

Eine Markuperweiterungsverwendung wird innerhalb eines Members, bei dem das Objekt eine Markuperweiterungsinstanz darstellt, im XAML-Knotenstream als Objektknoten gemeldet. Folglich wird eine Markuperweiterungsverwendung in der Knotenstreamdarstellung genauer dargestellt als eine Typkonverterverwendung, und sie enthält mehr Informationen. XamlMember-Informationen enthalten keine Informationen zu Markuperweiterung, da die Verwendung situationsbedingt ist und sich in jedem möglichen Markupfall ändert. Sie sind ebenso wie Typkonverter für Typen oder Member nicht dediziert oder implizit.

Markuperweiterungen werden in der Knotenstreamdarstellung auch dann als Objektknoten dargestellt, wenn die Markuperweiterung im XAML-Textmarkup in Attributform verwendet wurde, was häufig der Fall ist. Markuperweiterungsverwendungen, die ein explizites Objektelementformular verwendet haben, werden auf dieselbe Weise behandelt.

Innerhalb eines Markuperweiterungs-Objektknotens sind möglicherweise Member dieser Markuperweiterung vorhanden. Die XAML-Knotenstreamdarstellung behält die Verwendung dieser Markuperweiterung bei, egal ob es sich um eine Positionsparameterverwendung oder eine Verwendung mit expliziten benannten Parametern handelt.

Bei einer Positionsparameterverwendung enthält der XAML-Knotenstream eine durch die XAML-Sprache definierte _PositionalParameters-Eigenschaft, von der die Verwendung aufgezeichnet wird. Diese Eigenschaft ist ein generisches List<T>-Element mit Object-Einschränkung. Die Einschränkung ist ein Objekt und keine Zeichenfolge, da eine Positionsparameterverwendung u. U. geschachtelte Markuperweiterungsverwendungen enthalten könnte. Sie können die Liste durchlaufen und die Indexer für einzelne Listenwerte verwenden, um auf die Positionsparameter der Verwendung zuzugreifen.

Bei einer benannten Parameterverwendung wird jeder benannte Parameter als Memberknoten des Namens im Knotenstream dargestellt. Die Memberwerte sind nicht unbedingt Zeichenfolgen, da eine geschachtelte Markuperweiterungsverwendung vorhanden sein könnte.

Das ProvideValue-Element wird noch nicht von der Markuperweiterung aufgerufen. Es wird jedoch aufgerufen, wenn Sie einen XAML-Reader und einen XAML-Writer verbinden, sodass beim Untersuchen im Knotenstream WriteEndObject für den Markuperweiterungsknoten aufgerufen wird. Aus diesem Grund muss derselbe XAML-Schemakontext verfügbar sein wie für die Bildung des Objektdiagramms auf dem Ladepfad. Andernfalls kann ProvideValue in jeder Markuperweiterung Ausnahmen auslösen, da keine erwarteten Dienste verfügbar sind.

Durch XAML- und XML-Sprache definierte Member im XAML-Knotenstream

Bestimmte Member werden aufgrund von Interpretationen und Konventionen eines XAML-Readers in einem XAML-Knotenstream implementiert und nicht durch eine explizite XamlMember-Suche oder -Konstruktion. Häufig sind diese Member XAML-Direktiven. In einigen Fällen wird die Direktive durch das Lesen des XAML im XAML-Knotenstream eingefügt. Dies bedeutet, dass die Memberdirektive im ursprünglich eingegebenen XAML-Text nicht explizit angegeben wurde, der XAML-Reader die Direktive aber einfügt, um XAML-Strukturkonventionen zu entsprechen und Informationen im XAML-Knotenstream zu melden, bevor sie verloren gehen.

In der folgenden Liste sind alle Fälle aufgeführt, in denen ein XAML-Reader voraussichtlich einen XAML-Memberknoten für eine Direktive einfügt, und es wird beschrieben, wie dieser Memberknoten in den .NET Framework-XAML-Dienstimplementierungen identifiziert wird.

  • Initialisierungstext für einen Objektknoten: Der Name dieses Memberknotens ist _Initialization. Er stellt eine XAML-Direktive dar und ist im XAML-Namespace der XAML-Sprache definiert. Eine entsprechende statische Entität kann aus Initialization abgerufen werden.

  • Positionsparameter zu einer Markuperweiterung: Der Name dieses Memberknotens ist _PositionalParameters, und er wird im XAML-Sprachnamespace definiert. Er enthält immer eine generische Liste von Objekten, bei denen es sich um Positionsparameter handelt, die durch Trennung bei dem im Eingabe-XAML angegebenen ,-Trennzeichen vorab getrennt werden. Eine statische Entität für die Positionsparameterdirektive kann aus PositionalParameters abgerufen werden.

  • Unbekannter Inhalt: Der Name dieses Memberknotens ist _UnknownContent. Streng genommen handelt es sich um ein XamlDirective-Element und wird im XAML-Sprachnamespace definiert. Diese Direktive wird als Sentinel für Fälle verwendet, in denen ein XAML-Objektelement im Quell-XAML Inhalt aufweist, aber keine Inhaltseigenschaft im aktuell verfügbaren XAML-Schemakontext ermittelt werden kann. Sie können diesen Fall auch in einem XAML-Knotenstream beobachten. Prüfen Sie hierzu auf Member mit dem Namen _UnknownContent. Falls keine andere Aktion in einem Ladepfad-XAML-Knotenstream ausgeführt wird, löst der standardmäßige XamlObjectWriter beim Aufruf von WriteEndObject eine Ausnahme aus, wenn der _UnknownContent-Member für ein Objekt gefunden wird. Das standardmäßige XamlXmlWriter-Element wird nicht ausgelöst, und der Member wird als implizit behandelt. Sie können eine statische Entität für _UnknownContent von UnknownContent abrufen.

  • Auflistungseigenschaft einer Auflistung: Obwohl der unterstützende CLR-Typ einer für XAML verwendeten Auflistungsklasse normalerweise über eine dedizierte benannte Eigenschaft verfügt, die die Elemente der Auflistung enthält, ist diese Eigenschaft einem XAML-Typsystem vor der Unterstützungstypauflösung nicht bekannt. Stattdessen fügt der XAML-Knotenstream einen Items-Platzhalter als Member des XAML-Auflistungstyps ein. In der .NET Framework-XAML-Dienstimplementierung lautet der Name dieser Direktive/dieses Members im Knotenstream _Items. Eine Konstante für diese Direktive kann aus Items abgerufen werden.

    Beachten Sie, dass ein XAML-Knotenstream eine Items-Eigenschaft mit Elementen enthalten kann, die auf Grundlage der Unterstützungstypauflösung und des XAML-Schemakontexts nicht analysiert werden können. Beispiel:

  • In XML definierte Member: Die in XML definierten xml:base-, xml:lang- und xml:space-Member werden als XAML-Direktiven mit den Namen base, lang und space in den .NET Framework-XAML-Dienstimplementierungen gemeldet. Der Namespace hierfür ist der http://www.w3.org/XML/1998/namespace-XML-Namespace. Konstanten für jedes dieser Elemente kann von XamlLanguage abgerufen werden.

Knotenreihenfolge

In einigen Fällen ändert der XamlXmlReader die Reihenfolge von XAML-Knoten im XAML-Knotenstream gegenüber der Reihenfolge, in der die Knoten bei der Anzeige im Markup oder der Verarbeitung als XML angezeigt werden. Dadurch werden die Knoten so sortiert, dass der XamlObjectWriter den Knotenstream nur vorwärts verarbeiten kann. In den .NET Framework-XAML-Diensten ordnet der XAML-Reader Knoten neu, anstatt diese Aufgabe dem XAML-Writer zu überlassen. Dies dient zur Leistungsoptimierung für XAML-Objektwriterconsumer des Knotenstreams.

Bestimmte Direktiven sind speziell zum Bereitstellen weiterer Informationen für die Erstellung eines Objekts aus einem Objektelement vorgesehen. Diese Direktiven sind: Initialization, PositionalParameters, TypeArguments, FactoryMethod und Arguments. Die XAML-Reader der .NET Framework-XAML-Dienste versuchen, diese Direktive als erste Member im Knotenstream nach dem StartObject eines Objekts zu platzieren. Die Gründe dafür werden im nächsten Abschnitt erläutert.

XamlObjectWriter-Verhalten und Knotenreihenfolge

Das StartObject für einen XamlObjectWriter ist nicht notwendigerweise ein Signal für den XAML-Objektwriter, die Objektinstanz sofort zu erstellen. XAML umfasst mehrere Sprachfunktionen, bei denen ein Objekt mit zusätzlichen Eingaben initialisiert werden kann und das Erzeugen des anfänglichen Objekts nicht ausschließlich vom Aufrufen eines Standardkonstruktors abhängig ist, bevor Eigenschaften festgelegt werden. Zu diesen Funktionen zählen: XamlDeferLoadAttribute, Initialisierungstext, x:TypeArguments, Positionsparameter einer Markuperweiterung, Factorymethoden und zugehörige x:Arguments-Knoten (XAML 2009). In jedem dieser Fälle wird die tatsächliche Objekterstellung verzögert, und da der Knotenstream neu sortiert wird, kann der XAML-Objektwriter ein Verhalten verwenden, bei dem die Instanz tatsächlich jedes Mal erstellt wird, wenn ein Member gefunden wird, bei dem es sich nicht um eine Konstruktionsdirektive für diesen Objekttyp handelt.

GetObject

GetObject stellt einen XAML-Knoten dar, in dem ein XAML-Objektwriter den Wert der enthaltenden Eigenschaft des Objekts abrufen soll, anstatt ein neues Objekt zu erstellen. Ein typischer Fall, in dem ein GetObject-Knoten in einem XAML-Knotenstream vorkommt, ist ein Auflistungs- oder Wörterbuchobjekt, bei dem die enthaltende Eigenschaft im Objektmodell des Unterstützungstyps bewusst schreibgeschützt ist. In diesem Szenario wird die Auflistung oder das Wörterbuch häufig durch die Initialisierungslogik eines übergeordneten Typs erstellt und initialisiert (normalerweise leer).

Siehe auch

Referenz

XamlObjectReader

Konzepte

XAML-Dienste

Weitere Ressourcen

XAML-Namespaces für .NET Framework-XAML-Dienste