XAMLx

advertisement
XAML (Extensible Application Markup Language – расширяемый язык разметки
приложений) представляет собой язык разметки, используемый для создания экземпляров
разметки .Net. Главное назначение XAML – конструирование пользовательских
интерфейсов WPF.
Разработчики давно поняли, что создавать сложные графически насыщенные приложения
намного проще, если отделить графическую часть от лежащего в основе кода. Таким
образом, дизайнеры могут заниматься графикой, а разработчики – кодом.
В ходе работы над приложением ViewRidgeAssistant мы так или иначе будем
сталкиваться с задачами разработки пользовательского интерфейса, однако, важно
понимать, что поскольку курс носит название: «управление данными» и сильно ограничен
во времени, то и касаться нам придется весьма ограниченного подмножества языка
XAML(большая часть времени, безусловно, уйдет на рассмотрение элементов
управления).
Строго говоря, Visual Studio – далеко не единственный инструмент для работы с XAML,
и, вероятно, не самый удобный, но именно в нем нам предстоит работать.
Создадим новое приложение WPF и рассмотрим XAML-код его главного окна:
Выберем в обозревателе решений файл MainWindow.xaml. Его
XAML код выглядит следующим образом.
<Window x:Class="Vra.GUserInterface.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>
Что же это значит? На самом деле для компилятора это инструкция о том, что существует
виджет1 верхнего уровня <Window> , который представляет собой все окно и имеет
некоторые предустановленные атрибуты (а именно, высоту 350 px, ширину 525px,
«метку» MainWindow, отображаемую сверху). Это самое окно имеет имя
Vra.GUserInterface.MainWindow находится в 2-х предопределенных пространствах имен
(xmlns2="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ), о которых знает
приложение и в с которыми оно может работать, а так же в пространстве имен XAML. И
внутри этого элемента имеется еще один «вложенный» элемент <Grid>, представляющий
собой «сетку-невидимку», используемую при компоновке элементов управления.
Скажем пару слов о пространствах имен.
Пространство имён — некоторое множество, под которым подразумевается
модель, абстрактное хранилище или окружение, созданное для логической
группировки уникальных идентификаторов (то есть имён). Идентификатор, определенный
в пространстве имён, ассоциируется с этим пространством. Один и тот же идентификатор
может быть независимо определён в нескольких пространствах.
Не очень понятно, правда? Отнеситесь к пространству имен как к капсуле, хранящей код.
— это основное
пространство имен WPF. Оно охватывает все классы WPF, включая элементы
управления, которые применяются для построения пользовательских интерфейсов. В
нашем случае это пространство имен объявлено без префикса пространства имен и
становится пространством имен по умолчанию для всего документа. Другими словами,
каждый элемент автоматически помещается в это пространство имен.
http://schemas.microsoft.com/winfx/2006/xaml/presentation
http://schemas.microsoft.com/winfx/2006/xaml — пространство имен XAML. Оно
включает в себя различные служебные свойства XAML, которые позволяют влиять на то,
как интерпретируется документ. Данное пространство имен отображается на префикс x.
Это значит, что его можно применять, помещая префикс пространства имен перед именем
документа (как <x:ИмяЭлемента>).
Вернемся к нашему приложению. Сейчас оно
выглядит так как на рисунке справа. Мы уже
упоминали об элементе Grid, теперь остановимся на
нем чуть подробнее. Применение этого класса
является важной частью компоновки элементов или
на жаргоне программистов – верстки. Половина
всех усилий при проектировании пользовательского
интерфейса уходит
на организацию содержимого, чтобы она была
привлекательной, практичной и
1
2
Виджет (англ. WIndows gaDGET) – любой визуальный элемент графического интерфейса пользователя.
xmlns  это специальный атрибут в мире XML, который зарезервирован для
объявления пространства имен. Класс может существовать в нескольких пространствах
имен. По существующему соглашению пространства имен XML имеют форму URI,
которые выглядят так, будто указывают на некоторый адрес в интернете, хотя на самом
деле это не так.
гибкой. Но по-настоящему сложной задачей является адаптация компоновки элементов
интерфейса к различным размерам окна.
В WPF компоновка формируется с использованием разнообразных контейнеров.
Каждый контейнер обладает собственной логикой компоновки — некоторые
укладывают элементы в стопку, другие распределяют их по ячейкам сетки и т.д. Виджет
Grid как раз предоставляет возможность распределения элементов по ячейкам. Однако эти
ячейки нужно сначала создать. Давайте сделаем это, а затем скажем пару слов о
философии компоновки WPF.
На самом деле существует два способа разбить Grid3 на ячейки:
 при помощи визуального редактора
 при помощи кода XAML
Оба эти способа дадут одинаковый результат, некоторые предпочитают ручное написание
кода, однако, на первых порах это может оказаться достаточно сложной задачей.
Давайте переключимся на панель разработки, кликните мышью по центру нашего окошка,
так чтобы гарантировано попасть в пока невидимый Grid и добейтесь такого результата:
Наведите курсор на подсвеченную голубым область, если вы все сделали правильно, то
увидите, как стрелка курсора превратилась в черный крест. Представьте, что теперь мы
будем резать прямоугольный торт. Отмеряйте от левого края некоторое пространство для
первой части нашей сетки и кликните левой кнопкой мыши (другими словами, нарисуйте
первый крайний левый столбец). Таких Столбцов нам потребуется три. Результат должен
стать похож на следующий рисунок.
Обратите внимание, что нигде в коде XAML мы не присваивали имя элементу управления Grid. В
традиционных приложениях Windows Forms каждый элемент управления имеет имя. В приложении WPF
такого требования нет. Обращаться из приложения к этому элементу формы мы не планируем, поэтому он
так и останется у нас неименованным.
3
В процессе рисования среда показывала нам маленькую вкладочку,
расположенную в середине окошка нашего приложения (её хорошо видно на рисунке) с
изображение трех кнопок: «мишень», «звездочка» и «auto» (абсолютные, автоматические
и пропорциональные размеры).
 Абсолютные размеры. Выбирается точный размер с использованием
независимых от устройства единиц измерения. Это наименее удобная стратегия,
поскольку она недостаточно гибка, чтобы справиться с изменением размеров
содержимого, изменением размеров контейнера или локализацией.
 Автоматические размеры. Каждая строка и колонка получает в точности то
пространство, которое нужно, и не более. Это один из наиболее удобных режимов
изменения размеров.
 Пропорциональные размеры. Пространство разделяется между группой строк
и колонок.
Теперь нарисуйте для нас несколько строк в Grid’е, они нам пригодятся в дальнейшем, а
мы пока сделаем несколько ремарок по поводу философии компоновки:
В WPF компоновка определяется используемым контейнером. Хотя есть несколько
контейнеров, среди которых можно выбирать, "идеальное" окно WPF следует
описанным ниже ключевым принципам:
 Элементы (такие как элементы управления) не должны иметь явно
установленных размеров. Вместо этого они растут, чтобы уместить свое
содержимое.
Например, кнопка увеличивается при добавлении в нее текста. Можно
ограничить элементы управления приемлемыми размерами, устанавливая
максимальное и минимальное их значение.
 Элементы не указывают свою позицию в экранных координатах. Вместо этого
они упорядочиваются своим контейнером на основе размера, порядка и
(необязательно) другой информации, специфичной для контейнера компоновки.
Для добавления пробелов между элементами служит свойство Margin.
 Контейнеры компоновки "разделяют" доступное пространство между своими
дочерними элементами. Они пытаются обеспечить для каждого элемента его
предпочтительный размер (на основе его содержимого), если только позволяет
свободное пространство. Они могут также выделять дополнительное пространство
одному или более дочерним элементам.
 Контейнеры компоновки могут быть вложенными. Типичный пользовательский
интерфейс начинается с Grid — наиболее развитого контейнера, и содержит
другие контейнеры компоновки, которые организуют меньшие группы элементов,
такие как текстовые поля с метками, элементы списка, значки в панели
инструментов, колонка кнопок и т.д.
Хотя из этих правил существуют исключения, они отражают общие цели
проектирования WPF. Другими словами, если вы последуете этим руководствам при
построении
WPF-приложения, то получите лучший и более гибкий пользовательский интерфейс. На
самом деле для нас это далеко не самая главная задача, ведь наш курс очень косвенно
связан с WPF, а тем более XAML.
Вернемся с небес на землю: XAML-код нашего окошка теперь выглядит приблизительно
так:
<Window x:Class="Vra.GUserInterface.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 ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="55" />
<RowDefinition Height="55" />
<RowDefinition Height="55" />
<RowDefinition Height="53" />
<RowDefinition Height="52" />
<RowDefinition Height="*" />
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="61" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Теперь мы вынуждены извиниться перед читателем
за свое лукавство. В самом начале мы назвали элемент Grid
сеткой-невидимкой, однако, это не совсем так. У этого
элемента управления есть элегантное свойство
ShowGridLines, по умолчанию оно установлено в положение
false, и это абсолютно обосновано и правильно, потому что
видимость границ между строк и столбцов – есть ни что
иное, как помощь разработчику. Но теперь мы установили
его в положение true. Изменение можно провести вручную в
редакторе XAML или через панель свойств.
Предлагаю скомпилировать приложение и посмотреть, что получилось:
Почему мы не видим еще один столбец нашего грида? Попробуйте ответить на этот
вопрос самостоятельно.
По мере наполнения окна контентом, мы убедимся в полезности ShowGridLines атрибута, а
сейчас можете снова перевести его в состояние false, или просто продолжить работу.
Хорошо, остановим работу приложения. Теперь у нас есть все необходимые контейнеры,
давайте займемся элементами управления.
Самый простой из них – кнопка, с него и начнем. Добавим кнопку в ячейку, образованную
пересечением 1-й строки с нулевым4 столбцом, сделать это как всегда можно при помощи
перетаскивания элемента с панели или при помощи XAML. Должно получиться
примерно так:
Кроме перемещения по таблицам нам, естественно, требуется еще и управление данными,
для этого необходимо несколько виджетов, включая уже известный нам элемент
управления «button». Добавьте во 2-й столбец Grid’а 4-е кнопки: «добавить», «изменить»,
«удалить» и «обновить».
4
Нумерация строк и столбцов Grid, принято начинать с “0”, это следует помнить!
XAML- код у меня принял вид:
<Window x:Class="Vra.GUserInterface.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 ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="350*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!--Кнопки управления таблицами-->
<Button Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" Name="btnArtist"
Content="Художники" VerticalAlignment="Top" Width="75" Margin="1" />
<!--Кнопки управления данными-->
<Button Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right"
Content="Добавить" VerticalAlignment="Top" Width="75" Margin="1" />
<Button Grid.Row="2" Grid.Column="2" HorizontalAlignment="Right"
Content="Изменить" VerticalAlignment="Top" Width="75" Margin="1"/>
<Button Grid.Row="3" Grid.Column="2" HorizontalAlignment="Right"
Content="Удалить" VerticalAlignment="Top" Width="75" Margin="1"/>
<Button Grid.Row="4" Grid.Column="2" HorizontalAlignment="Right"
Content="Обновить" VerticalAlignment="Top" Width="75" Margin="1" />
Name="btnAdd"
Name="btnEdit"
Name="btnDelete"
Name="btnReload"
</Grid>
</Window>
Окно при этом выглядит так:
Добавьте оставшиеся кнопки для навигации по таблицам.
Как и в любом другом современном языке в XAML присутствует синтаксический сахар –
возможность реализации одного и того же действия разными способами. Так, например,
декларация элемента «кнопка», могла бы выглядеть еще и вот так:
<Button Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right" Name="btnAdd"
VerticalAlignment="Top" Width="75" Margin="1" >
<Button.Content>
<StackPanel>
<TextBlock>Добавить</TextBlock>
</StackPanel>
</Button.Content>
<Button.ToolTip>
<TextBlock>Добавление контента</TextBlock>
</Button.ToolTip>
</Button>
Учитывая, что StackPanel – контейнер, подобный Grid попробуйте ответить на несколько
вопросов:
 С какой кнопкой авторы провели преобразование?
 Что изменилось?
 Для чего в код включен виджет StackPanel? Что он из себя представляет? Можно
ли избежать его использования?
 Попробуйте поэкспериментировать с внешним видом кнопок.
Итак, у нас есть кнопки, но нет таблиц данных, давайте это исправим и gоместим на окно
компонент DataGrid – таблицу и назовем его dgArtists, добавим в нее соответствующие
колонки.
<!--Таблицы данных-->
<DataGrid x:Name="dgArtists" Grid.Row="1" Grid.Column="1" IsReadOnly="True"
AutoGenerateColumns="False" Grid.RowSpan="5" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Header="Имя" Binding="{Binding Path=Name}" />
<DataGridTextColumn Header="Год рождения" Binding="{Binding
Path=BirthYear}" />
<DataGridTextColumn Header="Год смерти" Binding="{Binding
Path=DeceaseYear}" />
<DataGridTextColumn Header="Национальность" Binding="{Binding
Path=Nationality}" />
</DataGrid.Columns>
</DataGrid>
Результат этих действий:
Download