Общее представление о понятиях и структурах потока узлов XAML
Средства чтения и записи XAML, реализованные в службах XAML платформы .NET Framework, основываются на конструктивной концепции потока узлов XAML. Поток узлов XAML — это концептуальное представление набора узлов XAML. В этом концептуальном представлении обработчик XAML по одному перебирает узлы структуры взаимосвязей в XAML-коде. В любой отдельно взятый момент времени в открытом потоке узлов XAML присутствует только одна текущая запись или текущая позиция, и многие аспекты API-интерфейса сообщают только информацию, доступную из этой позиции. Текущий узел в потоке узлов XAML может быть описан как объект, член или значение. Рассматривая XAML как поток узлов XAML, средства чтения XAML могут связываться со средствами записи XAML и позволяют программе просматривать содержимое потока узлов XAML, взаимодействовать с ним или изменять его в ходе операции с путем загрузки или путем сохранения, использующей XAML. Архитектура API-интерфейса средств чтения и записи XAML и концепция потока узлов XAML аналогичны архитектурам и концепциям, связанным с предыдущими средствами чтения и записи, такими как XML Document Object Model (DOM) и классы XmlReader и XmlWriter. В этом разделе рассматриваются понятия потока узлов XAML и описывается, как можно создавать процедуры, взаимодействующие в представлениями XAML на уровне узлов XAML.
В этом разделе содержатся следующие подразделы.
- Загрузка XAML-кода в средство чтения XAML
- Простейший цикл чтения узлов
- Работа с текущим узлом
- Обход узлов объектов и вход в них
- Преобразователи значений и поток узлов XAML
- Члены, определенные в языках XAML и XML в потоке узлов XAML
- Порядок узлов
- Связанные разделы
Загрузка XAML-кода в средство чтения XAML
В базовом классе XamlReader не объявляется конкретный способ загрузки исходного кода XAML в средство чтения XAML. Вместо этого способ загрузки, включая общие характеристики и ограничения на источник входных данных XAML, объявляется и реализуется производным классом. Например, средство чтения объектов XAML XamlObjectReader читает граф объектов, начиная с источника входных данных одного объекта, представляющего собой корень или основание графа. Затем XamlObjectReader производит из графа объектов поток узлов XAML.
Самым важным подклассом класса XamlReader, определенным в службах XAML платформы .NET Framework, является подкласс XamlXmlReader. Средство чтения XAML XamlXmlReader загружает исходный XAML-код, либо прямо — загружая текстовый файл из потока или заданного файла, либо косвенно — через связанный класс средства чтения, такой как TextReader. По завершении загрузки можно считать, что XamlReader содержит источник входных данных XAML во всей его полноте. Однако базовый API-интерфейс XamlReader разработан таким образом, чтобы средство чтения взаимодействовало с одним узлом XAML. При первой загрузке первым обнаруживаемым узлом оказывается корень XAML и его начальный объект.
Концепция потока узлов XAML
Читателям, более знакомым с доступом к XML-технологиям на основе модели DOM, метафоры "дерево" или запросов, удобно будет рассматривать поток узлов XAML следующим образом. Представьте себе, что загруженный XAML-код — это модель DOM или дерево, где каждый возможный узел полностью развернут и представлен в линейной форме. По мере продвижения по узлам может происходить "вход" и "выход" на уровни, которые присутствовали бы в модели DOM, однако в потоке узлов XAML их учет явным образом не ведется, поскольку к потоку узлов уровневая концепция не применима. Поток узлов имеет "текущую" позицию, но, если другие части потока не сохранены разработчиком в качестве ссылок, все аспекты потока узлов, кроме текущего узла-позиции, находятся вне видимости.
Концепция потока узлов XAML имеет заметное преимущество, состоящее в том, что после прохода через весь поток узлов разработчик может быть уверен в том, что обработано все XAML-представление; не нужно беспокоиться, что запрос, операция DOM или какое-либо другое нелинейное средство обработки информации пропустили какую-либо часть XAML-представления. По этой причине представление в виде потока узлов XAML идеально подходит как для соединения средств чтения XAML со средствами записи XAML, так и для построения системы, в которую разработчик может вставить собственный процесс, выполняемый между фазами чтения и записи операции обработки XAML. Во многих случаях порядок узлов в потоке узлов XAML намеренно оптимизируется или изменяется средствами чтения XAML относительно порядка узлов в исходном тексте, двоичных данных или графе объектов. Цель такого поведения — создание архитектуры обработки XAML, в которой средства записи XAML никогда не оказываются в положении, где им приходилось бы передвигаться "назад" по потоку узлов. В идеале все операции записи XAML должны быть способны выполняться на основании контекста схемы плюс текущей позиции потока узлов.
Простейший цикл чтения узлов
Простейший цикл чтения узлов для рассмотрения потока узлов XAML состоит из следующих этапов. Для рассмотрения циклов обработки узлов в этом разделе предполагается, что производится чтение текстового, понятного для человека XAML-файла с помощью средства чтения XAML XamlXmlReader. Ссылки в этом подразделе указывают на конкретный API-интерфейс цикла обработки узлов XAML, реализуемый в XamlXmlReader.
Убедитесь, что конец потока узлов XAML не достигнут (проверьте свойство IsEof или используйте возвращаемое значение метода Read()). Если достигнут конец потока, текущий узел отсутствует и следует выйти из процедуры.
Проверьте тип текущего предоставляемого узла в потоке узлов XAML, вызвав свойство NodeType.
При наличии напрямую соединенного средства записи объектов XAML в этой точке обычно вызывается метод WriteNode.
В зависимости от значения XamlNodeType, переданного в качестве типа текущего узла или текущей записи, вызовите один из следующих методов, чтобы получить информацию о содержимом узла.
Если NodeType — StartMember или EndMember, вызовите свойство Member, чтобы получить информацию о члене в виде XamlMember. Обратите внимание, что член может представлять собой директиву XamlDirective и, следовательно, не обязательно быть традиционным определенным в типе членом предыдущего объекта. Например, атрибут x:Name, примененный к объекту, выглядит как член XAML, у которого свойство IsDirective имеет значение true, а свойство Name члена имеет значение Name, плюс другие свойства также указывают, что это директива пространства имен XAML языка XAML.
Если NodeType — StartObject или EndObject, вызовите свойство Type, чтобы получить информацию об объекте в виде XamlType.
Если NodeType — Value, вызовите свойство Value. Узел является значением, только если он является самым простым из возможных выражений значений для члена или текстом инициализации объекта (следует, однако, принимать во внимание поведение преобразования типов, описанное в одном из следующих подразделов этого раздела).
Если NodeType — NamespaceDeclaration, вызовите свойство Namespace, чтобы получить информацию о пространстве имен для узла пространства имен.
Вызовите Read, чтобы средство чтения XAML перешло к следующему узлу в потоке узлов XAML, и повторите описанные действия.
Поток узлов XAML, предоставляемый средствами чтения XAML служб XAML платформы .NET Framework, всегда обеспечивает полный глубокий просмотр всех возможных узлов. В число типичных способов управления потоком для цикла обработки узлов XAML входит определение тела в операторе while (reader.Read()) и ветвление по свойству NodeType в каждой точке-узле цикла обработки узлов.
Если поток узлов находится в конце файла, текущий узел будет пуст (null).
Простейший цикл с участием средства чтения и средства записи будет подобен следующему примеру.
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);
}
Этот простой пример цикла узлов XAML пути загрузки явно связывает средство чтения XAML и средство записи XAML, не делая при этом ничего, что отличалось бы от использования метода XamlServices.Parse. Но затем эта простая структура разворачивается для применения к пользовательскому сценарию чтения или записи. Ниже приведены некоторые возможные сценарии.
Организуйте ветвление по свойству NodeType. Выполните различные действия в зависимости от типа считываемого узла.
Не вызывайте метод WriteNode ни в одном из случаев. Вызовите метод WriteNode только в некоторых случаях со свойством NodeType.
В пределах логики для конкретного типа узла проведите анализ особенностей этого узла и действуйте согласно этим особенностям. Например, можно записать только те объекты, которые происходят из какого-либо отдельного пространства имен XAML, затем отсеять или отложить все объекты, происходящие не из этого пространства имен XAML. Также при обработке пользовательских членов можно отсеять или иным образом повторно обработать все директивы XAML, которые не поддерживаются пользовательской системой XAML.
Определите пользовательское средство записи XamlObjectWriter, которое могло бы переопределить методы Write*, возможно, выполняя сопоставление типов, которое минует контекст схемы XAML.
Создайте средство чтения XamlXmlReader для использования контекста схемы XAML, отличного от существующего по умолчанию, чтобы нестандартное поведение XAML использовалось и средством чтения, и средством записи.
Доступ к XAML без использования цикла обработки узлов
Потенциально кроме цикла обработки узлов XAML существуют и другие способы работы с представлением XAML. Например, может существовать средство чтения XAML, которое может читать индексированный узел или обращаться к узлам напрямую, используя x:Name, x:Uid или другие идентификаторы. Службы XAML платформы .NET Framework не предоставляют полную реализацию, но предоставляют рекомендуемый шаблон с помощью служб и типов поддержки. Дополнительные сведения см. в разделах IXamlIndexingReader и XamlNodeList.
Совет |
---|
Корпорацией Майкрософт также подготовлен внештатный выпуск, называемый Microsoft XAML Toolkit.Этот внештатный выпуск пока находится на стадии предварительной версии.Однако, если вы готовы работать с компонентами предварительных версий, в Microsoft XAML Toolkit можно найти несколько интересных ресурсов для работы с XAML и статического анализа XAML.В состав Microsoft XAML Toolkit входят API-интерфейс DOM для XAML, поддержка анализа FxCop, а также контекст схемы XAML для Silverlight.Дополнительные сведения см. в разделе Microsoft XAML Toolkit. |
Работа с текущим узлом
Большинство сценариев, предполагающих использование цикла обработки узлов XAML, не ограничивается чтением узлов. В большинстве сценариев выполняется обработка текущих узлов логики и передача по одному каждого из узлов в реализацию средства записи XamlWriter.
В типичном сценарии пути загрузки средство чтения XamlXmlReader производит поток узлов XAML, узлы XAML обрабатываются в соответствии с логикой разработчика и контекстом схемы XAML, а затем передаются средству записи XamlObjectWriter. Затем разработчик интегрирует полученный граф объектов в свое приложение или платформу.
В типичном сценарии пути сохранения средство чтения XamlObjectReader читает граф объектов, затем выполняется обработка отдельных узлов XAML, и средство записи XamlXmlWriter выводит сериализованный результат в текстовый файл XAML. Основная идея состоит в том, что оба пути (и сценария) предусматривают одновременную работу с только одним узлом XAML, и узлы XAML доступны для стандартизированной обработки, определяемой системой типов XAML и API-интерфейсами служб XAML платформы .NET Framework.
Кадры и область действия
Цикл обработки узлов XAML предполагает перебор потока узлов XAML линейным образом. Поток узлов углубляется в объекты, в члены, содержащие другие объекты, и т. д. Часто полезно следить за областью в потоке узлов XAML, реализуя концепцию кадра и стека. Это особенно верно во время активной настройки текущего потока узлов. Поддержка кадра и стека, реализуемая разработчиком в составе логики цикла обработки узлов, может подсчитывать области StartObject (или GetObject) и EndObject по мере углубления в структуру узлов XAML, если рассматривать структуру с позиций модели DOM.
Обход узлов объектов и вход в них
Когда первый узел в потоке узлов открывается средством чтения XAML, он является узлом начального объекта корневого объекта. По определению этот объект всегда является однообъектным узлом и не имеет одноранговых узлов. В любом реальном примере использования XAML у корневого объекта будет одно или несколько свойств, содержащих дополнительные объекты, и у этих свойств будут узлы членов. Далее, узлы членов обладают одним или несколькими узлами объектов и могут оканчиваться узлом значений. Корневой объект обычно определяет области видимости имен XAML, которые синтаксически присваиваются в качестве атрибутов в текстовой разметке XAML, однако сопоставляются с типом узла Namescope в представлении потока узлов XAML.
Рассмотрите следующий пример XAML (это произвольный код XAML, не обеспеченный существующими типами в платформе .NET Framework). Допустим, что в данной объектной модели FavorCollection является коллекцией List<T> из Favor, Balloon и NoiseMaker могут быть присвоены Favor, свойство Balloon.Color резервируется объектом Color подобно тому, как в WPF цвета определяются как известные имена цветов, а Color поддерживает преобразователь типов для синтаксиса атрибутов.
Разметка XAML |
Получаемый поток узлов XAML |
---|---|
<Party |
Узел Namespace для Party |
xmlns="PartyXamlNamespace"> |
Узел StartObject для Party |
<Party.Favors> |
Узел StartMember для Party.Favors |
Узел StartObject для неявной коллекции FavorCollection |
|
Узел StartMember для свойства элементов неявной коллекции FavorCollection |
|
<Balloon |
Узел StartObject для Balloon |
Color="Red" |
Узел StartMember для Color Узел Value для строки значения атрибута "Red". EndMember для Color |
HasHelium="True" |
Узел StartMember для HasHelium Узел Value для строки значения атрибута "True" EndMember для HasHelium |
> |
EndObject для Balloon |
<NoiseMaker>Loudest</NoiseMaker> |
Узел StartObject для NoiseMaker Узел StartMember для _Initialization Узел Value для строки значения инициализации "Loudest" Узел EndMember для _Initialization EndObject для NoiseMaker |
Узел EndMember для свойства элементов неявной коллекции FavorCollection |
|
Узел EndObject для неявной коллекции FavorCollection |
|
</Party.Favors> |
EndMember для Favors |
</Party> |
EndObject для Party |
В потоке узлов XAML можно полагаться на следующее поведение.
Если узел Namespace существует, он добавляется в поток непосредственно перед узлом StartObject, в котором объявлено пространство имен XAML, с префиксом xmlns. Снова взгляните на предыдущую таблицу с кодом XAML и примером потока узлов. Обратите внимание, что узлы StartObject и Namespace фактически транспонируются относительно своих позиций объявления в текстовой разметке. Это иллюстрирует, что узлы пространства имен всегда следуют в потоке узлов перед узлом, к которому они применяются. Основанием использования такой конструкции является крайняя важность информации пространства имен для средств записи объектов, поэтому эта информация должна быть известна до того, как средство записи объектов будет пытаться сопоставить типы или иным образом обработать объект. Размещение информации о пространстве имен XAML перед его областью приложения в потоке облегчает задачу обработки потока узлов в установленном порядке.
По указанной выше причине именно с одного или нескольких узлов Namespace начинается прочтение в большинстве случаев реального использования разметки при обходе узлов с начала, а не с корневого объекта StartObject.
За узлом StartObject может следовать узел StartMember, Value или непосредственно EndObject. За ним никогда непосредственно не следует другой узел StartObject.
За узлом StartMember может следовать узел StartObject, Value или непосредственно EndMember. За ним может следовать узел GetObject — для членов, где значение должно быть получено из существующего значения родительского объекта, а не из узла StartObject, который создал бы экземпляр нового значения. Также за ним может следовать узел Namespace, который применяется к следующему узлу StartObject. За ним никогда непосредственно не следует другой узел StartMember.
Узел Value представляет значение само по себе; значения EndValue не существует. За ним может следовать только узел EndMember.
Текст инициализации XAML объекта, который может быть использован конструкцией, не образует структуру Object-Value. Вместо этого создается выделенный узел члена для члена с именем _Initialization, и этот узел члена содержит строку значения инициализации. Если он существует, _Initialization всегда является первым членом StartMember. _Initialization может уточняться в некоторых представлениях служб XAML при помощи пространства имен XAML языка XAML, чтобы прояснить, что _Initialization не является определенным свойством в резервных типах.
Сочетание Член-Значение представляет параметр атрибута данного значения. В конечном итоге в обработке этого значения может быть задействован преобразователь значений, и значение представляет собой простую строку. Тем не менее, такой вариант не рассматривается, пока средство записи объектов XAML обрабатывает этот поток узлов. Средство записи объектов XAML обладает необходимым контекстом схемы XAML, сопоставлением системы типов и другой поддержкой, необходимой для преобразования значений.
За узлом EndMember может следовать узел StartMember для последующего члена или узел EndObject для владельца члена.
За узлом EndObject может следовать узел EndMember. Также за ним может следовать узел StartObject в случаях, когда эти объекты являются одноранговыми элементами коллекции. Или за ним может следовать узел Namespace, который применяется к следующему узлу StartObject.
- В исключительном случае закрытия всего потока узлов за корневым объектом EndObject ничего не следует; средство чтения достигает конца файла, а метод Read возвращает значение false.
Преобразователи значений и поток узлов XAML
Преобразователем значений называется какое-либо расширение разметки, преобразователь типов (включая сериализаторы значений) или другой выделенный класс, о котором в системе типов XAML сообщается как о преобразователе значений. В потоке узлов XAML употребление преобразователя типов и употребление расширения разметки обладают совершенно разными представлениями.
Преобразователи типов в потоке узлов XAML
Набор атрибутов, который в конечном итоге приводит к употреблению преобразователя типов, в потоке узлов XAML передается как значение члена. Поток узлов XAML не пытается произвести экземпляр объекта преобразователя типов и передать ему значение. Использование преобразования, реализованного в преобразователе типов, требует вызова контекста схемы XAML и использования его для сопоставления типов. Даже определение того, какой класс преобразователя типов необходимо использовать для обработки значения, косвенно требует использовать контекст схемы XAML. При использовании контекста схемы XAML по умолчанию эту информацию можно получить из системы типов XAML. Если информация о классе преобразователя типов необходима на уровне потока узлов XAML до подключения к средству записи XAML, получить ее можно из информации объекта XamlMember устанавливаемого члена. В противном случае входные данные должны быть сохранены в потоке узлов XAML в виде простого значения до тех пор, пока не будут выполнены остальные операции, требующие системы сопоставления типов и контекста схемы XAML, например создание объекта средством записи объектов XAML.
Например, рассмотрите следующее общее описание определения класса и соответствующее ему употребление XAML.
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"/>
Текстовое представление потока узлов XAML для данного употребления можно выразить следующим образом.
Объект StartObject с типом XamlType, представляющим GameBoard
Член StartMember с классом XamlMember, представляющим BoardSize
Узел Value с текстовой строкой "8x8"
EndMember соответствует BoardSize.
EndObject соответствует GameBoard.
Обратите внимание, что в данном потоке узлов нет экземпляра преобразователя типов. Но информацию о преобразователе типов можно получить, вызвав свойство XamlMember.TypeConverter объекта XamlMember в отношении BoardSize. При наличии допустимого контекста схемы XAML можно также вызвать методы преобразователя, получив экземпляр из свойства ConverterInstance.
Расширения разметки в потоке узлов XAML
Об употреблении расширения разметки в потоке узлов XAML сообщается как об узле объекта внутри члена, где объект представляет экземпляр расширения разметки. Таким образом, употребление расширения разметки более явно представлено в потоке узлов, чем употребление преобразователя типов, и несет в себе больше информации. Сведения XamlMember могут не сообщить ничего о расширении разметки, поскольку употребление зависит от ситуации и меняется в каждом возможном случае разметки; оно не является выделенным и внутренне заложенным согласно типу или члену в отличие от преобразователей типов.
Расширения разметки представляются в потоке узлов в качестве узлов объектов, даже если расширение разметки было употреблено в виде атрибута в текстовой разметке XAML (как это часто бывает). Употребление расширения разметки в виде явных объектных элементов обрабатывается таким же способом.
Внутри узла объекта расширения разметки могут находиться члены этого расширения разметки. Представление потока узлов XAML сохраняет употребление этого расширения разметки, будь то употребление позиционных параметров или употребление с явно именованными параметрами.
Для употребления позиционных параметров поток узлов XAML содержит определенное языком XAML свойство _PositionalParameters, в которое записывается это употребление. Это свойство является универсальным перечнем List<T> с ограничением Object. Ограничение является объектом, а не строкой, поскольку употребление позиционного параметра, вероятно, может содержать случаи употребления вложенного расширения разметки. Для доступа к позиционным параметрам из употребления необходимо выполнить итерации по списку и использовать индексаторы для отдельных значений списка.
Для употребления именованных параметров каждый именованный параметр представляется как узел члена с соответствующим именем в потоке узлов. Значения членов не обязательно являются строками, поскольку возможно употребление вложенного расширения разметки.
Метод ProvideValue из расширения разметки еще не вызван. Однако он вызывается, если связать средство чтения XAML и средство записи XAML таким образом, что в узле расширения разметки при его рассмотрении в потоке узлов будет вызываться метод WriteEndObject. Поэтому обычно необходимо обладать доступом к тому же контексту схемы XAML, который использовался бы для формирования графа объектов на пути загрузки. В противном случае метод ProvideValue из любого расширения разметки может создать здесь исключения, поскольку у него нет доступа к ожидаемым службам.
Члены, определенные в языках XAML и XML в потоке узлов XAML
Некоторые члены вводятся в поток узлов XAML за счет интерпретаций и соглашений средства чтения XAML, а не через явный поиск или создание объекта XamlMember. Эти члены часто являются директивами XAML. В некоторых случаях директива вводится в поток узлов XAML в результате собственно чтения XAML-кода. Иными словами, в первоначальном входном XAML-тексте не указана явным образом директива-член, однако средство чтения XAML вставляет эту директиву для удовлетворения требований соглашения о структуре XAML и передачи некоторой информации в потоке узлов XAML, прежде чем эта информация будет потеряна.
Ниже перечислены все случаи, в которых средство чтения XAML должно вводить узел члена XAML для директивы, с указанием того, как соответствующий узел члена идентифицируется в реализациях служб XAML платформы .NET Framework.
Текст инициализации для узла объекта: этот узел члена имеет имя _Initialization; он представляет собой директиву XAML и определен пространстве имен XAML языка XAML. Для него можно получить статическую сущность из свойства Initialization.
Позиционные параметры для расширения разметки: этот узел члена имеет имя _PositionalParameters; он определен в пространстве имен XAML языка XAML. Он всегда содержит универсальный список объектов (каждый из которых является позиционным параметром, предварительно отделенным по разделительному символу ,), переданный во входных данных XAML. Для директивы позиционных параметров можно получить статическую сущность из свойства PositionalParameters.
Неизвестное содержимое: данный узел члена имеет имя _UnknownContent. Строго говоря, это класс XamlDirective, и он определен в пространстве имен XAML языка XAML. Эта директива используется в качестве граничной метки для случаев, когда объектный элемент XAML содержит какое-либо содержимое в исходном коде XAML, но по доступному в данный момент контексту схемы XAML невозможно определить ни одно свойство содержимого. Такой случай можно обнаружить в потоке узлов XAML, проверив члены с именем _UnknownContent. Если в потоке узлов XAML пути загрузки не предпринимаются никакие другие действия, средство записи по умолчанию XamlObjectWriter создает исключение при попытке выполнения метода WriteEndObject, если в каком-либо объекте встретится член _UnknownContent. Средство записи по умолчанию XamlXmlWriter исключений на создает и рассматривает этот член как неявный. Для _UnknownContent можно получить статическую сущность из UnknownContent.
Свойство коллекции в коллекции: хотя резервный тип CLR класса коллекции, используемый для XAML, обычно имеет выделенное именованное свойство, в котором хранятся элементы коллекции, системе типов XAML это свойство не будет известно до разрешения в резервный тип. Вместо этого в потоке узлов XAML вводится заполнитель Items в качестве члена типа коллекции XAML. В реализации служб XAML платформы .NET Framework XAML эта директива (член) в потоке узлов имеет имя _Items. Константу для этой директивы можно получить из свойства Items.
Обратите внимание, что поток узлов XAML может содержать свойство Items с элементами, не поддающимися синтаксическому анализу на основе разрешения в резервный тип и контекста схемы XAML. Например:
Определенные в языке XML члены: определенные в языке XML члены xml:base, xml:lang и xml:space в реализациях служб XAML платформы .NET Framework передаются в виде директив XAML с именами base, lang и space. Пространством имен для этих членов является пространство имен XML http://www.w3.org/XML/1998/namespace. Константы для каждого из них можно получить из XamlLanguage.
Порядок узлов
В некоторых случаях средство чтения XamlXmlReader изменяет порядок узлов XAML в потоке узлов XAML относительно порядка, в котором они следуют при просмотре в разметке или обработке в виде XML. Узлы упорядочиваются так, чтобы средство записи XamlObjectWriter могло обрабатывать поток узлов, двигаясь только вперед. В службах XAML платформы .NET Framework порядок узлов изменяется средством чтения XAML, а не средством записи XAML — в целях оптимизации производительности для средств записи объектов XAML, потребляющих поток узлов.
Некоторые директивы предназначены специально для предоставления дополнительной информации для создания объекта из объектного элемента. К этим директивам относятся: Initialization, PositionalParameters, TypeArguments, FactoryMethod, Arguments. Средства чтения XAML служб XAML платформы .NET Framework пытаются поместить эти директивы в качестве первых членов в потоке узлов — после узла StartObject объекта — по причинам, описанным в следующем подразделе.
Поведение XamlObjectWriter и порядок узлов
С точки зрения XamlObjectWriter узел StartObject не обязательно является для средства записи объектов XAML сигналом к немедленному созданию экземпляра объекта. В XAML предусмотрено несколько языковых возможностей, которые позволяют инициализировать объект дополнительными входными данными, а не только вызывать конструктор по умолчанию для производства первоначального объекта и только затем устанавливать свойства. К этим возможностям относятся: XamlDeferLoadAttribute; текст инициализации; x:TypeArguments; позиционные параметры расширения разметки; фабричные методы и связанные с ними узлы x:Arguments (XAML 2009). Во всех этих случаях фактическое создание объекта откладывается и, поскольку поток узлов переупорядочивается, средство записи объектов XAML может использовать поведение с фактическим создания экземпляра при обнаружении начального члена, не представляющего собой именно директиву создания для данного типа объекта.
GetObject
GetObject представляет собой узел XAML, где вместо создания нового объекта средство записи объектов XAML должно получить значение свойства, содержащего объект. Типичный случай, когда в потоке узлов XAML встречается узел GetObject — объект коллекции или объект словаря, где свойство-контейнер намеренно является доступным только для чтения в объектной модели резервного типа. В этом сценарии коллекция или словарь зачастую создаются и инициализируются (обычно пустыми) логикой инициализации типа-владельца.