При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. |
Основы языка XAML
Цель
Получить первоначальное представление о назначении и области применения языка XAML, составить представление о структуре XAML-документа, изучить основные синтаксические конструкции.
Основные сведения о языке XAML
Построение пользовательских интерфейсов для WPF- и Silverlight-приложений осуществляется с применением языка расширенной разметки приложений XAML (Extensible Application Markup Language). XAML-документ содержит разметку, описывающую внешний вид и поведение окна или страницы приложения, а связанные с ним файлы кода C# - логику приложения. Язык XAML обеспечивает разделение процесса дизайна приложения (графической части) и разработки бизнес-логики (программного кода) между дизайнерами и разработчиками. WPF XAML является подмножеством языка XML и позволяет описывать WPF-содержимое таких элементов как векторная графика, элементы управления и документы.
XAML базируется на языке расширенной разметки XML (Extensible Markup Language) и его синтакс определяется следующими правилами [ 3 ] :
- каждый элемент XAML-документа отображается на некоторый экземпляр класса .NET. Имя такого элемента в точности соответствует имени класса. Например, элемент < Button > служит для WPF инструкцией для построения объекта класса Button;
- элементы XAML можно вкладывать друг в друга. Вложение элементов разметки обычно отображает вложенность элементов интерфейса;
- свойства класса определяются с помощью атрибутов или с помощью вложенных дескрипторов со специальным синтаксисом.
Язык XAML характеризуется самоописанием. Каждый элемент в XAML-документе представляет имя типа (такие как Button, Window или Page ) в рамках заданного пространства имен. Атрибуты элементов используются для задания свойств ( Name, Height, Width и т.п.) и событий ( Click, Load и т.д.) соответствующих объектов.
При создании WPF-приложения MyFirstWpfProject VisualStudio генерирует следующий XAML-документ.
<Window x:Class="MyFirstWpfProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>
XAML-документ WPF-приложения MyFirstWpfProject начинается с дескриптора < Window...>. Все дескрипторы XAML-документа начинаются символами <, а завершаются символами >. Любой XAML-документ состоит из XAML-элементов. Каждый XAML-документ (XAML-элемент) начинается открывающимся дескриптором (например < Window >), за которым следует содержимое документа (например, текстовая строка или другие XAML-элементы). В открывающем дескрипторе могут присутствовать описания атрибутов (например, Class, xmlns, Title, Height, Width и др.). XAML-документ (XAML-элемент) должен завершаться закрывающимся дескриптором (например, /> или < /Window >). Текст XAML-документа должен содержать один корневой элемент – элемент верхнего уровня вложенности. В XAML-документе WPF-приложения MyFirstWpfProject таким элементом является < Window >. В корневой элемент могут быть добавлены другие XAML-элементы. В рассматриваемом XAML-документе это элемент < Grid >.
В процессе компиляции XAML-документа WPF-приложения синтаксический анализатор переводит XAML файлы в файлы языка двоичной разметки приложений BAML ( Binary Application Markup Language ), которые затем встраиваются в виде ресурсов в сборку проекта. Для построения классов WPF-приложения синтаксический анализатор использует пространство имен, которое определено в корневом дескрипторе XAML-документа.
Пространство имен в XAML-документе задается с помощью атрибута xmlns. В приведенном выше документе объявлено два базовых пространства имен:
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" – это базовое пространство имен WPF, которое охватывает все классы WPF, включая элементы управления, которые применяются при построении пользовательского интерфейса. Так как данное пространство имен объявлено без префикса, то оно распространяется на весь XAML-документ;
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" – пространство имен XAML. Оно включает различные свойства утилит XAML, которые позволяют влиять на то, как XAML-документ следует интерпретировать. Данное пространство имен отображается на префикс x. Этот префикс можно помещать перед именем элемента ( x:ИмяЭлемента ).
Второе пространство имен используется для включения специфичных для XAML лексем – "ключевых слов" [ [ 9 ] ]. В табл.1.1 приведены наиболее часто используемые ключевые слова XAML.
В WPF-приложениях кроме базовых применяют специальные, необязательные пространства имен:
- http://schemas.openxmlformats.org/markup-compatibility/2006 - пространство имен XAML, связанное с проблемой совместимости разметки с рабочей средой. Данное пространство имен используется для информирования синтаксического анализатора XAML о том, какую информацию необходимо обработать, а какую – проигнорировать;
- http://schemas.microsoft.com/expression/blend/2008 - пространство имен XAML, поддерживаемое программами Expression Blend и Visual Studio. Данное пространство имен используется для установки размеров графической панели для страницы.
В атрибуты объекта Window могут быть добавлены следующие XAML-описания.
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="600"
Данное XAML-описание объявляет необязательные пространства имен с префиксами mc и d. Свойства DesignHeight и DesignWidth находятся в пространстве имен, помеченном префиксом d. Данные свойства определяют, что во время разработки проекта приложения в дизайнере Visual Studio окно должно иметь размеры 300x600. Свойство Ignorable находится в пространстве имен, помеченном префиксом mc, и информирует синтаксический анализатор о том, что он должен игнорировать часть XAML-документа, помеченные префиксом d.
В XAML-документе WPF-приложения часто возникает необходимость обеспечить доступ к каким-либо другим пространствам имен проекта. В этом случае необходимо определить новый префикс и задать пространство имен. Если в проекте имеется пространство имен MyFirstWpfProject.Commands, то подключение его к XAML-документу WPF-приложения будет иметь следующий вид (command – используется в качестве префикса).
xmlns:command="clr-namespace: MyFirstWpfProject.Commands"
Префикс (command) используется для ссылки на пространство имен в XAML-документе. Лексеме clr-namespace присваивается название пространства имен .NET в сборке.
Для описания класса в XAML-документе используется атрибут Class. Строка XAML-документа
<Window x:Class="MyFirstWpfProject.MainWindow" ...>
предписывает создать класс MyFirstWpfProject.MainWindow на базе класса Window. Префикс x атрибута Class определяет то, что данный атрибут помещается в пространство имен XAML. Класс MainWindow генерируется автоматически во время компиляции. Для части класса автоматически генерируется код (частичный (partial) класс):
namespace MyFirstWpfProject { /// <summary> /// Логика взаимодействия для MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } }
Когда выполняется компиляция приложения, XAML-файл, который определяет пользовательский интерфейс ( MainWindow.xaml ), транслируется в объявление типа CLR , которое объединяется с логикой приложения из файла класса отдельного кода ( MainWindow.xaml.cs ).
Метод InitializeComponent() генерируется во время компиляции приложения и в исходном коде не присутствует.
Для программного управления элементами управления, описанными в XAML-документе необходимо для элемента управления задать XAML атрибут Name. Так для задания имени элементу Grid необходимо записать следующую разметку:
<Grid Name="grid"> </Grid>
Простые свойства задаются в XAML-документе в соответствии со следующим синтаксисом:
ИмяСвойства ="значение"
Например, Name = "grid1"
При необходимости задать свойство, которое является полноценным объектом, используются сложные свойства в соответствии с синтаксисом "свойство-элемент":
Родитель.ИмяСвойства
Например, для контейнера StackPanel нам необходимо задать градиентную кисть для заливки панели, что определяется атрибутом Background. Это реализуется с помощью дескрипторов <StackPanel.Background> . . . </StackPanel.Background>.
Для задания значения свойства из выделенного класса используется расширение разметки, которое обеспечивает расширение грамматики XAML новой функциональностью. Расширения разметки могут использоваться во вложенных дескрипторах или в XAML-атрибутах. Когда это используется в атрибутах, то необходимо применять фигурные скобки {...}.
Расширения разметки используют следующий синтаксис:
{КлассРасширенияРазметки Аргумент }
Расширения разметки реализуются классами, дочерними от класса System.Windows.Markup.MarkupExtention. Базовый класс MarkupExtention имеет метод ProvideValue(), который предоставляет нужное значение для атрибута. Например, для задания атрибуту Foreground объекта Button статического свойства, определенного в другом классе, необходимо создать следующее XAML-описание.
<Button Foreground="{x:Static SystemColors.ActiveCaptionBrush}" />
При компиляции синтаксический анализатор создаст экземпляр класса Static Extention, затем вызовет метод ProvideValue(), который извлечет нужное значение и установит его для свойства Foreground.
Расширения разметки могут использоваться как вложенные свойства.
Присоединенные свойства описывают свойства, которые могут применяться к нескольким элементам управления, но которые определены в другом классе. В WPF-приложениях присоединенные свойства часто используются для управления компоновкой элементов интерфейса. Синтаксис присоединенных свойств следующий.
ОпределяющийТип.ИмяСвойства
Например, если необходимо расположить кнопку в нулевой строке сетки, то необходимо сделать следующее XAML-описание.
<Button . .. Grid.Row="0" > .... </Button>
Здесь присоединенным свойством является Grid.Row, то есть свойство Row элемента Grid, которое не является свойством объекта Button. Свойство Row присоединяется к свойствам объекта Button, поскольку данный объект располагается в контейнере Grid.
Атрибуты объектов могут использоваться для присоединения обработчиков событий, используя следующий синтаксис.
ИмяСобытия = "ИмяМетодаОбработчикаСобытия"
Например, для кнопки событию её нажатия Click можно установить обработчик события Exit_Click.
<Button Name="Exit" Content="Выход" Click="Exit_Click" />
Определяя в XAML-описании обработчик Exit_Click, необходимо в коде класса иметь метод с корректной сигнатурой. Ниже приведен код, который генерируется автоматически при создании описания обработчика события в XAML-описании.
private void Exit_Click(object sender, RoutedEventArgs e) { . . . . . }
Ключевые термины
Язык расширенной разметки приложений XAML, язык двоичной разметки приложений BAML, XAML-документ, XAML-элемент, корневой элемент XAML-документа, дескриптор, язык двоичной разметки приложений, синтаксический анализатор, базовое пространство имен XAML-документа, ключевые слова XAML, лексема clr-namespace, префикс в XAML-документе, простое свойство в XAML-документе, сложное свойство в XAML-документе, расширение разметки в XAML-документе, присоединенные свойства в XAML-документе, присоединение обработчиков событий в XAML-документе.
Краткие итоги
В данной теме были рассмотрены основные синтаксические конструкции языка XAML и приведены простые примеры их реализации. Проектирование WPF-приложений требует от разработчика понимания структуры и содержания XAML-документа, описывающего интерфейс создаваемой системы. В последующих темах курса будут рассматриваться различные аспекты построения WPF- и Silverlight-приложений и необходимым условием эффективной работы создателя таких систем является знание основ языка XAML.
Ресурсы для углубленного изучения
- XAML в WPF // http://msdn.microsoft.com/ru-ru/library/ms747122.aspx
- [ 3 ] , стр.53 – 76.
- [ 4 ] , стр. 48 – 81.
- [ 6 ] , стр.834 – 853.
- [ 9 ] , стр. 475 – 504.
Вопросы для самопроверки
- Что отображает каждый элемент XAML-документа?
- Можно ли вкладывать друг в друга элементы XAML?
- Как определяются в XAML-документе свойства класса?
- Как должен начинаться и завершаться XAML-документ?
- Поясните назначение пространства имен http://schemas.microsoft.com/winfx/2006/xaml.
- Приведите синтаксис простых свойств, задаваемых в XAML-документе.
- Приведите синтаксис сложных свойств, задаваемых в XAML-документе.
- Приведите синтаксис расширения разметки.
- Приведите синтаксис присоединенных свойств.
- Приведите синтаксис присоединения обработчиков событий.