2013-12-11 2 views
16

Что происходит внутри между загрузкой XAML (или BAML) и получением корневого объекта (например, Window)?Как XAML интерпретируется и выполняется во время выполнения?

Что я впервые всплываю в голове, так это то, что Reflecton используется для создания объектов, их свойств и т. Д. Но, может быть, я ошибаюсь?

Возможно, кто-нибудь может объяснить, как анализируется и выполняется XAML/BAML во время выполнения или дает ссылку на хорошую статью с объяснением?

Для того, чтобы мой вопрос немного понятнее, давайте рассмотрим краткий пример:

<Button Margin="10">OK</Button> 

Таким образом, синтаксический анализатор видит, что объект Button должен быть создан, что его свойство Margin должен быть установлен 10, и его содержимое должно быть установлено на «ОК». Как это делается? Используя Reflection (плюс TypeConverters и т. Д.)?

ответ

25

В ваших файлах .xaml.cs вы можете заметить, что классы, поддерживающие ваши скомпилированные файлы XAML, помечены как классы partial. Задача сборки XAML создает второй файл .cs с другим сектором частичного класса, содержащим реализацию метода IComponentConnector.InitializeComponent(), который вызывается конструктором по умолчанию в коде позади. Этот метод в основном проходит через XAML (который фактически находится в форме BAML в этой точке) и использует его для «исправления» вновь созданного объекта, в отличие от создания нового объекта из источника XAML, что и произойдет, если вы должны были использовать XamlReader для загрузки или анализа объекта.

Итак, когда вы создаете экземпляр нового скомпилированного объекта XAML (например, UserControl), любой код предшествует вызову InitializeComponent() в конструкторе. Затем все свойства и обработчики событий, установленные в файле XAML, будут обработаны во время вызова до InitializeComponent(), после чего конструктор возобновится. Это может быть полезно знать, поскольку вы можете захотеть убедиться, что определенные свойства будут установлены до или после обработки файла XAML.

Относительно того, как анализируется XAML, он по существу считывается как поток узлов XAML, представляющих присвоения свойств, объявления объектов и т. Д., Которые выполняются по порядку услугами в System.Xaml. Этот поток узлов основан на общей объектной модели, которая, возможно, была построена из потока BAML, XML-документа (например, файла .xaml), другого экземпляра объекта и т. Д. BAML, будучи более компактным, чем формат на основе XML , обычно быстрее разбирается.


Добавление: В примере вы добавили, вы спросите, как анализатор видит, что Button объект должен быть создан и Margin набор. Короткий ответ: это зависит. В частности, это зависит от контекста схемы, используемого для чтения потока XAML.

Часть XAML анализатор использует свою собственную систему типа, из которых по крайней мере две реализации:

  1. стандартной системы типа CLR, основанные на отражении и System.ComponentModel;
  2. Система типа WPF, которая расширяет # 1 путем включения специальной поддержки свойств зависимостей и маршрутизируемых событий.

Это, основанное на моем воспоминании о XAML языка Spec, примерно то, что происходит:

  1. Часть XAML парсер встречает StartObject узел типа Button, который (для стандартных отображений пространств имен WPF) разрешается до System.Windows.Controls.Button. Это говорит парсеру, что ему нужно создать экземпляр объекта Button, который он делает, вызывая его конструктор по умолчанию через отражение.
  2. Следующий узел в потоке - это узел StartMember с именем участника Margin. Модель типа для контекста схемы WPF разрешит это для свойства зависимостей Margin.
  3. A Value узел приходит далее, что говорит синтаксическому анализатору установить значение "10" (строка). Парсер видит, что тип свойства Thickness несовместим со строковым значением. Он консультирует свою систему типов, чтобы узнать, существует ли атрибут [ValueSerializer] в свойстве Margin, который может быть использован для преобразования строки; такой атрибут не существует. Он проверяет свойство для атрибута [TypeConverter]; опять же, он не находит ничего. Он ищет атрибут [TypeConverter] самого типа Thickness и находит тот, который инструктирует его использовать ThicknessConverter для преобразования строкового значения в Thickness. Он делает это. Поскольку Margin является свойством зависимости, он использует API SetValue() для установки значения свойства; если бы это было свойство CLR, оно использовало бы отражение или PropertyDescriptor.
  4. Узел EndMember указывает синтаксическому анализатору завершить назначение свойства.
  5. Парсер встречает Value узел с контентом "OK". Парсер знает, что он создает сложный объект, поэтому контент не может представлять весь объект. Он ищет атрибут [ContentProperty] на Button и его супертипах; он находит один на ContentControl, что указывает, что значение должно использоваться для установки свойства Content (которое получает разрешение на соответствующее свойство зависимостей). Content - object, поэтому он непосредственно присваивает значение string (опять же, используя SetValue()).
  6. Следующий узел: EndObject, который сообщает парсеру, что он закончил обработку объекта Button.

Обратите внимание, что я использовал термин «парсер» для упрощения. Честно говоря, ничто из этого не происходит на этапе синтаксического анализа (если даже существует «синтаксический» этап). То, что вы можете себе представить как этап «синтаксического анализа», - это просто построение потока узлов XAML. Создание и/или совокупность объявленного объекта (ов) фактически происходит путем подачи этого потока в XamlObjectWriter, который представляет собой просто реализацию XamlWriter, которая записывает узлы XAML в объект (в отличие от XML-документа или потока BAML). На высоком уровне происходит только две вещи:

  1. XamlReader превращает что-то в поток узлов XAML.
  2. XamlWriter превращает поток узлов XAML во что-то.

В случае compled XAML ресурса, время компиляции трубы сборки задачи выхода из XamlXmlReader в BamlWriter, чтобы «компилирование» XAML.Во время выполнения вход BamlReader отправляется в XamlObjectWriter для создания или «исправления» корневого объекта.

Как только вы все это осознаете, вы можете начать распознавать XAML как мощный формат сериализации и персистентности, а не просто язык для создания пользовательских интерфейсов.

+0

Майк, спасибо за ваш хороший ответ. Ваше добавление - это то, что мне нужно. Таким образом, построение дерева объектов с помощью механизма WPF предполагает интенсивное использование отражения в нашем микроприложении - создание объекта Button, определение того, какой TypeConverter использовать, построение TypeConverter, выяснение, что Margin является свойством зависимостей и т. Д. Право? – WpfNewbie

+1

Да, в системе типа XAML много отражений. –

+0

Отличный ответ !! – nawfal

Смежные вопросы