Компиляция XAML

24

Код и не компилированный XAML

Одним из наиболее интересных способов использования XAML является разбор его на лету с помощью XamlReader. Например, предположим, что вы начинаете со следующего содержимого в файле Window1.xaml:

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Button Name="Btn1" Margin="40">Кликни меня!</Button>
</DockPanel>

Во время выполнения можно загрузить это содержимое в активное окно. Ниже показан код, который делает это:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.IO;

namespace WpfApplication1
{
    public class Class1 : Window
    {
        private Button Btn1;
        public Class1() { }
        public Class1(string xamlFile)
        {
            InitializedComponent(xamlFile);
        }

        private void InitializedComponent(string xamlFile)
        {
            // Новая форма
            this.Width = this.Height = 300;
            this.Left = this.Top = 100;
            this.Title = "Моя кнопка";

            // Получаем содержимое XAML из внешнего файла
            DependencyObject rootElement;
            using (FileStream fs = new FileStream(xamlFile, FileMode.Open))
            {
                rootElement = (DependencyObject)XamlReader.Load(fs);
            }
            this.Content = rootElement;
            Btn1 = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, "Btn1");

            // Обработчик события клика
            Btn1.Click += btn1_Click;
        }

        private void btn1_Click(object sender, RoutedEventArgs e)
        {
            Btn1.Content = "Спасибо!";
        }
    }   
}

Здесь конструктор получает имя файла XAML в качестве аргумента (в данном случае — Window1.xaml). Он открывает FileStream и использует метод Load() класса XamlReader для преобразования содержимого этого файла в DependencyObject, являющийся базой, от которой наследуются элементы управления WPF. Этот объект DependencyObject может быть помещен внутрь контейнера любого типа (например, Panel), но в данном примере он используется как содержимое для всего окна.

В этом примере из файла XAML загружается элемент — объект DockPanel. В качестве альтернативы можно было бы загрузить все окно XAML. В данном случае объект, возвращенный XamlReader.Load(), потребуется привести к типу Window и затем вызвать его метод Show() или ShowDialog() для того, чтобы отобразить его.

Чтобы манипулировать элементом, например, кнопкой в файле Window1.xaml, необходимо найти соответствующий объект — элемент управления в динамически загруженном содержимом. Для этих целей предназначен элемент LogicalTreeHelper. Он позволяет производить поиск по всему дереву объектов — элементов управления, погружаясь на столько уровней, на сколько необходимо, пока не будет найден объект с указанным именем. Обработчик затем присоединяется к событию Button.Click.

Очевидно, что динамическая загрузка XAML не будет столь же эффективной, как компиляция XAML в BAML с последующей загрузкой BAML во время выполнения, особенно в случае сложного пользовательского интерфейса. Тем не менее, она открывает ряд возможностей для построения динамических пользовательских интерфейсов.

Например, можно было бы создать оператор общего назначения для опроса, который читает файл формы из веб-службы и затем отображает соответствующие элементы управления (метки, текстовые поля, флажки и т.п.). Файл формы может быть обычным документом XAML с дескрипторами WPF, который загружается в существующую форму с помощью XamlReader. Чтобы собрать результаты, как только форма опроса заполнена, понадобится просто перечислить все элементы управления вводом и собрать их содержимое. Другое преимущество подхода с несвязанными файлами XAML в готовом проекте состоит в том, что они позволяют использовать улучшения в стандарте XAML 2009.

Код и скомпилированный XAML

Это метод, применяемый Visual Studio, который обладает рядом преимуществ, уже затронутых ранее:

В Visual Studio используется двухэтапный процесс компиляции приложений WPF. Первый этап — компиляция XAML-файлов в BAML. Например, если проект включает файл по имени Window1.xaml, то компилятор создаст временный файл Window1.baml и поместит его в подпапку obj\Debug (в папке проекта). В то же время для окна создается частичный класс с использованием выбранного языка. Например, если применяется C#, то компилятор создаст файл по имени Window1.g.cs в папке obj\Debug. Здесь g означает generated (сгенерированный).

Частичный класс включает следующие вещи:

Частичный класс не включает кода для создания экземпляра и инициализации элементов управления, потому что эта задача выполняется механизмом WPF, когда BAML-код обрабатывается методом Application.LoadComponent().

В процессе компиляции компилятор XAML должен создать частичный класс. Это возможно, только если используемый вами язык поддерживает модель .NET Code DOM. Языки C# и VB поддерживают Code DOM, но если используется язык от независимого поставщика, следует убедиться, что эта поддержка доступна, прежде чем создавать приложения со скомпилированным XAML.

Когда завершается этап компиляции XAML в BAML, Visual Studio использует компилятор соответствующего языка, чтобы скомпилировать код и сгенерированные файлы частичного класса. В случае приложения C# эту задачу решает компилятор csc.exe. Скомпилированный код становится единой сборкой (*.exe), и BAML для каждого окна встраивается как отдельный ресурс.

Только XAML

Ранее было показано, как использовать XAML из приложения на основе кода. Разработчики для .NET будут заниматься этим большую часть времени. Однако также возможно использовать файл XAML без создания кода. Это называется несвязанный XAML-файл. Несвязанные файлы XAML могут открываться непосредственно в Internet Explorer. (Предполагается, что платформа .NET Framework установлена.)

Если файл XAML использует код, он не может быть открыт в браузере Internet Explorer. Однако можно построить браузерное приложение под названием ХВАР, в котором это ограничение преодолено.

К этому моменту создание несвязанного XAML-файла может показаться относительно бесполезным. В конце концов, какой смысл в пользовательском интерфейсе без управляющего им кода? Однако, изучая XAML, вы откроете несколько средств, которые полностью декларативны. К ним относится анимация, триггеры, привязка данных и ссылки (которые могут указывать на другие несвязанные файлы XAML). Используя эти средства, можно строить очень простые XAML-файлы без кода. Они не будут выглядеть как завершенные приложения, но позволят делать несколько больше, чем статические страницы HTML.

Чтобы попробовать несвязанную страницу XAML, внесите в файл .xaml следующие изменения:

Пройди тесты
Лучший чат для C# программистов