Прочитав эту главу, вы научитесь:
• характеризовать особенности обычного приложения для универсальной платформы Windows;
• создавать масштабируемый пользовательский интерфейс для приложения универсальной платформы Windows, способный адаптироваться к различным форм-факторам и ориентации устройств;
• создавать стили и применять их к приложению для универсальной платформы Windows.
В последних версиях Windows появилась платформа для создания и запуска приложений с высокой степенью интерактивности, постоянно подключенным и сенсорно управляемым пользовательским интерфейсом и поддержкой встроенных сенсорных устройств. Обновленная система безопасности приложений и модель их жизненного цикла изменяют способ совместной работы пользователей и приложений. Эта платформа называется Windows Runtime (WinRT), и на нее уже встречались ссылки в этой книге. Среду Visual Studio можно использовать для создания WinRT-приложений, подстраиваемых под широкий спектр форм-факторов устройств, от планшетных компьютеров до настольных вычислительных систем с большими экранами высокого разрешения. Используя Windows 8 и Visual Studio 2013, вы можете также публиковать эти приложения в магазине Windows Store в качестве принадлежащих ему приложений.
Помимо этого, для разработки и реализации приложений, запускаемых на устройствах под управлением Windows Phone 8, вы можете воспользоваться средой Windows Phone SDK 8.0, интегрированной в Visual Studio. В этих приложениях много общего с их ближайшими родственниками, разработанными для планшетных и настольных компьютеров, но они работают в более ограниченной среде, имеющей, как правило, более скромные ресурсы и требующей поддержки другой разметки пользовательского интерфейса. Вследствие этого приложения, разрабатываемые под Windows Phone 8, используют другую версию WinRT, которая называется Windows Phone Runtime, и у вас есть возможность вывести приложения Windows Phone 8 на рынок в качестве приложений магазина Windows Phone Store. С помощью имеющегося в Visual Studio шаблона Библиотека классов (переносимая) вы можете создать библиотеку классов для совместного использования логики приложения и бизнес-логики с работающим под Windows приложением для планшетных и настольных компьютеров и приложением для Windows Phone 8. Но приложения в магазине Windows Store и в магазине Windows Phone Store — это разные приложения, отличающиеся друг от друга предоставляемыми функциями.
Впоследствии компания Microsoft стремилась сблизить эти две платформы и сократить количество различий. Кульминацией этой стратегии стала операционная система Windows 10 с приложениями универсальной платформы Windows, где используется скорректированная версия WinRT, которая и называется универсальной платформой (Universal Windows Platform (UWP)). Используя UWP, можно создавать приложения, которые будут работать на широком спектре устройств под управлением Windows 10, при этом исключается необходимость сопровождения отдельных баз исходного кода. Кроме множества смартфонов, планшетных и настольных компьютеров, UWP доступна также на устройствах Xbox.
ПРИМЕЧАНИЕ Платформа UWP определяет основной набор функций и средств их реализации. В UWP устройства делятся на семейства настольных компьютеров, мобильных устройств, Xbox-устройств и т.д. Для каждого семейства определяется набор API-интерфейсов и устройств, на которых они реализуются. В дополнение к этому в семействе универсального устройства определяется основной набор функций и средств их реализации, доступных на всех семействах устройств. Библиотеки, доступные для каждого семейства устройств, включают условные методы, позволяющие приложению тестировать, на каком семействе устройств оно в данный момент выполняется.
В этой главе дается краткое описание концепций, положенных в основу платформы UWP, которое поможет вам приступить к использованию среды Visual Studio 2015 для создания приложений, работающих в этом окружении. В главе будет рассмотрен ряд функций и инструментальных средств, включенных в Visual Studio 2015 для создания UWP-приложений, с помощью которых будет создано приложение, соответствующее особенностям интерфейса Windows 10. Основное внимание будет уделено изучению способов реализации пользовательского интерфейса, способного к масштабированию и адаптации к различным разрешающим возможностям и форм-факторам устройств, а также способов применения стилей для придания приложению особого оформления.
ПРИМЕЧАНИЕ Чтобы представить полноценный трактат о создании UWP-приложений, в книге слишком мало места. Поэтому ее последние главы сконцентрированы на рассмотрении основных принципов построения интерактивных приложений, использующих пользовательский интерфейс Windows 10. Более подробную информацию о создании UWP-приложений можно получить на странице «Руководство по работе с приложениями универсальной платформы Windows (UWP)» веб-сайта компании Microsoft по адресу .
Многие современные мобильные устройства и планшетные компьютеры позволяют пользователям взаимодействовать с приложениями с использованием сенсорного ввода. UWP-приложение нужно проектировать на основе этого стиля пользовательского восприятия (user experience (UX)). Windows 10 включает обширную коллекцию элементов управления на основе сенсорного ввода, которые работают также с мышью и клавиатурой. Вам в своих приложениях не нужно разделять свойства сенсорного ввода и мыши — просто проектируйте приложения под сенсорный ввод, а пользователи в силу своих предпочтений или использования устройств, не поддерживающих сенсорный ввод, по-прежнему смогут работать с ними, используя мышь и клавиатуру.
Способ, которым графический пользовательский интерфейс (GUI) реагирует на жесты для обеспечения обратной связи с пользователем, может существенно улучшить восприятие ваших приложений — они будут производить впечатление программных продуктов, созданных на высоком профессиональном уровне. Имеющиеся в среде Visual Studio 2015 шаблоны для универсальных приложений Windows включают библиотеку анимации, которой можно воспользоваться в ваших приложениях для приведения этой обратной связи к стандартам операционной системы и программного обеспечения, предоставляемого компанией Microsoft.
ПРИМЕЧАНИЕ Жестикуляция относится к ручным операциям, которые пользователь может выполнять на устройствах сенсорного ввода. Например, пользователь может прикоснуться к элементу пальцем, и реакция на этот жест будет такой же, как и на щелчок на этом элементе мышью. Но жесты могут быть гораздо выразительнее простых операций, фиксируемых при использовании мыши. Например, вращательный жест предполагает прикосновение к экрану двумя пальцами и их перемещение по воображаемой дуге окружности, в обычном приложении, разработанном под Windows 10, этот жест заставит пользовательский интерфейс выполнить вращение выбранного объекта в направлении, показанном движениями пальцев пользователя. К прочим жестам относятся разведение пальцев на экране для увеличения элемента и его более детального отображения, прикосновение, кратковременное удержание пальца на элементе для получения о нем дополнительной информации (этот жест аналогичен щелчку правой кнопкой мыши) и проведение пальцем по экрану для выбора элемента и его перемещения в другое место экрана.
Платформа UWP предназначена для работы на широком спектре устройств с различными размерами и разрешениями экранов. Поэтому при создании UWP-приложения нужно сконструировать свои программные средства так, чтобы они адаптировались к среде, в которой выполняются, и автоматически масштабировались под размер экрана и ориентацию устройства. Такой подход откроет для ваших программ более широкий рынок сбыта. Кроме того, многие современные устройства со встроенными сенсорами и акселерометрами способны определять свою ориентацию в пространстве и скорость, с которой пользователь меняет ее. UWP-приложения могут адаптировать свою разметку под наклоны и вращения устройства, позволяя пользователю работать в наиболее комфортном для него режиме. Следует также понимать, что мобильность является ключевым требованием для многих современных приложений и, применяя UWP-приложения, пользователи могут перемещаться, а их данные могут мигрировать по облачным хранилищам, на каких бы устройствах ни запускалось ваше приложение в данный конкретный момент.
Жизненный цикл UWP-приложения не такой, как у обычного приложения, предназначенного для настольного компьютера. Вам следует разрабатывать приложения, способные работать на таких устройствах, как смартфоны, которые приостанавливают свое выполнение, когда пользователь переключается на другое приложение, а затем возобновляют его, когда пользователь к ним возвращается. На устройствах с ограниченным объемом ресурсов такой подход способствует их экономии, а также уменьшению расхода энергии аккумуляторной батареи. Операционная система Windows может даже принять решение о закрытии приостановленного приложения, если обнаружится, что ей нужно высвободить системные ресурсы, например память. При следующем запуске приложение должно обладать способностью возвращаться на то место, где было приостановлено его выполнение. Это означает, что при определенном стечении обстоятельств вам следует быть готовым управлять в своем коде информацией о состоянии приложения, сохранять эту информацию на жестком диске и впоследствии восстанавливать ее.
ПРИМЕЧАНИЕ Дополнительные сведения об управлении жизненным циклом UWP-приложения можно найти на странице «Guidelines for app suspend and resume» веб-сайта Microsoft по адресу .
После создания нового UWP-приложения его можно запаковать с помощью инструментальных средств, предоставляемых средой Visual Studio 2015, и выложить в магазин Windows Store. Другие пользователи могут зайти в магазин, скачать ваше приложение и установить его на своем устройстве. Вы можете взимать плату за свои приложения или открыть к ним бесплатный доступ. Возможность использования этого механизма распространения и развертывания зависит от того, насколько ваше приложение надежно и в какой степени оно соответствует политикам безопасности, установленным компанией Microsoft. Когда приложение выкладывают в магазине Windows Store, оно подвергается ряду проверок, позволяющих убедиться, что в нем не содержится вредоносный код и оно соответствует требованиям безопасности, предъявляемым к UWP-приложениям. Эти ограничения, связанные с выполнением требований безопасности, предписывают порядок доступа вашего приложения к ресурсам компьютера, на который оно устанавливается. Например, изначально UWP-приложение не может вести запись непосредственно в файловую систему или прослушивать входящие сетевые запросы (это два стиля поведения, присущие вирусам и другим вредоносным программам). Но если ваше приложение нуждается в выполнении операций, на которые наложены ограничения, их можно указать в качестве возможностей в данных манифеста приложения, хранящегося в файле Package.appxmanifest. Эта информация записывается в метаданных вашего приложения и сигнализирует Microsoft о необходимости выполнения дополнительных тестов для проверки способа использования приложением этих функциональных средств.
Файл Package.appxmanifest является XML-документом, но вы можете его отредактировать в среде Visual Studio с помощью конструктора манифеста. Пример показан на рис. 25.1. Здесь для указания подпадающих под ограничения операций, которые приложение может выполнять, используется вкладка Возможности.
Рис. 25.1
В этом примере приложение объявляет, что ему нужно:
• получать данные, поступающие из Интернета, но не иметь возможности действовать в качестве сервера и не иметь доступа к локальной сети;
• считывать и записывать данные, хранящиеся в папке документов пользователя;
• иметь доступ к информации GPS, позволяющей определить местоположение устройства;
• получать доступ к видеоканалу встроенной камеры или внешней веб-камеры.
Эти требования становятся известны пользователю, и в любом случае он может отключить настройки после установки приложения, а приложение должно обнаружить подобное отключение и быть готовым к откату, альтернативному решению или отключению функциональной возможности, требующей выполнения данных функций.
ПРИМЕЧАНИЕ Дополнительные сведения о возможностях, поддерживаемых UWP-приложением, можно найти на странице «Объявления возможностей приложения» веб-сайта Microsoft по адресу .
Хватит теории, давайте приступим к созданию UWP-приложения.
Проще всего создать UWP-приложение, воспользовавшись шаблонами универсального приложения Windows, включенными в среду Visual Studio 2015, работающую под управлением Windows 10. Многие основанные на графическом интерфейсе пользователя приложения, реализованные в предыдущих главах, использовали шаблон Пустое приложение, являющийся вполне подходящим местом для начала работы.
В следующих упражнениях вы будете проектировать пользовательский интерфейс для простого приложения, разрабатываемого для вымышленной компании под названием Adventure Works. Эта компания производит и поставляет велосипеды и сопутствующие товары. Приложение позволит пользователю вводить и править сведения о клиентах компании Adventure Works.
В меню Файл среды Visual Studio 2015 укажите на пункт Создать, а затем щелкните на пункте Проект.
В левой панели диалогового окна Создание проекта раскройте пункт Шаблоны, затем подпункт Visual C#, подпункт Windows и щелкните на пункте Универсальные. Щелкните в средней панели на значке Пустое приложение (Универсальное приложение Windows). Наберите в поле Имя строку Customers. Наберите в поле Расположение строку \Microsoft Press\VCSBS\Chapter 25 с префиксом в виде вашей папки документов. Щелкните на кнопке OK. Будет создано новое приложение, и в окно редактора будет выведен файл App.xaml.cs. Пока его можно проигнорировать.
В обозревателе решений дважды щелкните на файле MainPage.xaml. Появится окно конструктора с отображением пустой страницы. Чтобы добавить нужные приложению элементы управления, их, как было показано в главе 1 «Добро пожаловать в C#», можно перетащить из панели элементов. Но для выполнения задач данного упражнения поучительнее будет обратиться к определяющей формат XAML-разметке. У нее должен быть следующий вид:
<Page
x:Class="Customers.MainPage"
xmlns=""
xmlns:x=""
xmlns:local="using:Customers"
xmlns:d=""
xmlns:mc=""
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
</Grid>
</Page>
Форма начинается с XAML-тега <Page> и завершается закрывающим тегом </Page>. Все, что находится между этими двумя тегами, определяет содержимое страницы.
В атрибутах <Page>-тега содержится несколько объявлений в формате xmlns:id = "…". Это объявления пространства имен XAML, которые действуют аналогично директивам C# using в том смысле, что вводят элементы в область видимости. Многие элементы управления и другие элементы, которые можно добавлять на страницу, определены в этих пространствах имен XAML, и большинство этих объявлений можно проигнорировать. Но здесь есть одно довольно любопытное объявление, на которое следует обратить внимание:
xmlns:local="using:Customers"
Это объявление помещает элементы в область видимости C# Customers. В коде XAML на классы и другие типы в этом пространстве имен можно ссылаться, используя для них префикс local. Пространство имен Customers сгенерировано для кода в вашем приложении.
В обозревателе решений раскройте узел MainPage.xaml, а затем дважды щелкните на файле MainPage.xaml.cs, чтобы его содержимое отобразилось в окне редактора. Из предыдущих упражнений этой книги можно было понять, что это файл C#, в котором находятся логика приложения и обработчики событий для формы. Он имеет следующий вид (инструкции using, находящиеся в верхней части файла, для экономии пространства опущены):
// Документацию по шаблону элемента "Пустая страница" см. по адресу
//
namespace Customers
{
/// <summary>
/// Пустая страница, которую можно использовать саму по себе или для
/// перехода внутри фрейма.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
}
}
В этом файле определяются типы в пространстве имен Customers. Страница реализуется классом по имени MainPage, являющимся наследником класса Page. Класс Page реализует исходные функциональные возможности XAML-страницы для UWP-приложения, и вам остается лишь написать в классе MainPage код, определяющий логику, специфичную для вашего приложения.
Вернитесь в окне конструктора к файлу MainPage.xaml. Посмотрите на XAML-разметку для страницы и убедитесь, что тег <Page> включает следующий атрибут:
x:Class="Customers.MainPage"
Этот атрибут подключает XAML-разметку, определяющую формат страницы, к классу MainPage, предоставляющему логику, положенную в основу страницы.
Это основное подключение простого UWP-приложения. Разумеется, ценность графического приложения определяет способ предоставления информации пользователю. Но не всегда все так просто, как кажется. Проектирование привлекательного и удобного в использовании графического интерфейса требует особых навыков, которые имеются не у всех разработчиков (я это знаю, поскольку сам испытываю их дефицит). Но многие художники-графики, обладающие подобными навыками, не являются программистами и, обладая способностью спроектировать великолепный пользовательский интерфейс, могут быть не в состоянии реализовать логику, придающую этому интерфейсу полезные свойства. К счастью, среда Visual Studio 2015 позволяет отделить дизайн пользовательского интерфейса от бизнес-логики, в результате чего художник-график и разработчик могут сотрудничать, создавая приложение, имеющее великолепный внешний вид и отличные рабочие параметры. Разработчику остается сконцентрироваться на основной разметке приложения, а работу по стилевому оформлению предоставить художнику.
Основа разметки пользовательского интерфейса для UWP-приложения заключается в понимании того, как его можно заставить масштабироваться и подстраиваться под разные форм-факторы, доступные устройствам, на которых пользователи могут запускать приложение. Способы достижения способности к масштабированию будут исследованы в следующих упражнениях.
Обратите внимание на то, что в панели инструментов в верхней части окна конструктора (рис. 25.2) имеются раскрывающийся список, позволяющий выбрать разрешение и форм-фактор рабочей области конструирования, и две кнопки, позволяющие выбрать ориентацию (книжную или альбомную) для тех устройств, которые поддерживают вращение (планшеты и смартфоны его поддерживают, а настольные компьютеры — нет). Цель в том, чтобы позволить вам использовать эти настройки для быстрого просмотра того, как пользовательский интерфейс будет выглядеть на различных устройствах.
Изначально разметка показывается для смартфона с 5-дюймовым экраном в книжной ориентации. Выберите в раскрывающемся списке 0" Desktop (1280 x 720) 100% масштаб. Обратите внимание на то, что исходной ориентацией для этого форм-фактора является альбомная. Посмотрите на XAML-разметку для страницы MainPage. Она содержит один элемент управления Grid:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
</Grid>
ПРИМЕЧАНИЕ Обращать внимание на способ указания свойства фона Background для элемента управления Grid пока не нужно. Это пример использования стиля, а стили будут рассмотрены в этой главе чуть позже.
Рис. 25.2
При построении масштабируемых и гибких пользовательских интерфейсов основную роль играет понимание того, как работает элемент управления Grid. Элемент Page может содержать только один элемент, и, как показано в следующем примере, если нужно, элемент управления Grid можно заменить элементом управления Button (кнопка).
ПРИМЕЧАНИЕ Не набирайте следующий код, он показан исключительно в учебных целях:
<Page
...
<Button Content="Click Me"/>
</Page>
Но польза от получившегося в результате приложения весьма сомнительна, потому что форма, содержащая кнопку и больше ничего не показывающая, вряд ли завоюет приз как самое удачное приложение в мире. При попытке добавления на страницу второго элемента управления, например текстового поля типа TextBox, ваш код не откомпилируется и будет выдана ошибка (рис. 25.3).
Элемент управления Grid предназначен для того, чтобы помочь добавить на страницу несколько элементов. Этот элемент является примером элемента управления типа «контейнер» — в нем могут содержаться несколько других
Рис. 25.3
элементов управления, и вы можете указать позиции этих элементов внутри данного контейнера. Допустимо использование и других элементов управления типа «контейнер». Например, элемент управления StackPanel автоматически размещает содержащиеся в нем элементы управления в вертикальной раскладке с позиционированием каждого элемента управления непосредственно под его предшественником.
В данном упражнении Grid будет использован для содержания элементов управления, необходимых пользователю для ввода и просмотра данных о клиенте.
Добавьте на страницу элемент управления TextBlock, перетащив его из панели элементов или введя строку <TextBlock /> непосредственно на панели XAML в пустой строке после открывающего тега <Grid>:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock />
</Grid>
СОВЕТ Если панель элементов не появилась, щелкните на пункте Панель элементов в меню Вид, и она должна быть выведена в левой части окна. Также учтите, что вам можно набрать код элемента управления непосредственно в окне XAML для данной страницы — перетаскивать элементы из панели элементов совсем не обязательно.
Этот блок текста типа TextBlock предоставляет заголовок страницы. Установите для элемента управления типа TextBlock свойства, воспользовавшись значениями, показанными в табл. 25.1.
Таблица 25.1
Свойство | Значение |
HorizontalAlignment | Left |
Margin | 400,90,0,0 |
TextWrapping | Wrap |
Text | Adventure Works Customers |
VerticalAlignment | Top |
FontSize | 50 |
Эти свойства можно установить, воспользовавшись окном Свойства или путем ввода эквивалентной XAML-разметки, показанной жирным шрифтом, в окне XAML:
<TextBlock HorizontalAlignment="Left" Margin="400,90,0,0" TextWrapping="Wrap"
Text="Adventure Works Customers" VerticalAlignment="Top" FontSize="50"/>
Получившийся в результате текст должен отобразиться в окне конструктора (рис. 25.4).
Рис. 25.4
Заметьте, что при перетаскивании элемента управления из панели элементов в форму с двух сторон элемента появляются линии, соединяющие эти стороны с краями элемента управления типа «контейнер», куда помещается перетаскиваемый элемент, с указанием расстояния между соединяемыми точками. В предыдущем примере соединительные линии для элемента управления типа TextBlock содержали надписи 400 (от левого края контейнера) и 90 (от его верхнего края). Если в ходе выполнения программы размеры элемента управления Grid изменяются, TextBlock будет перемещаться для сохранения этого расстояния, что в данном случае может привести к изменению расстояния в пикселах, на которое TextBlock будет удален от правого и нижнего краев элемента Grid. Можно указать край или края, к которым элемент будет привязан, задав значения свойств HorizontalAlignment и VerticalAlignment. Расстояние от краев, к которым осуществлена привязка, указывается в свойстве Margin. В данном примере для свойства HorizontalAlignment элемента TextBlock установлено значение Left, а для свойства VerticalAlignment — значение Top, благодаря чему элемент управления привязан к левому и верхнему краям контейнера. Свойство Margin имеет четыре значения, в которых указываются расстояния от левой, верхней, правой и нижней сторон (именно в таком порядке) элемента управления до соответствующих краев контейнера. Если одна из сторон элемента управления не привязана к краю контейнера, в свойстве Margin соответствующее значение можно установить равным 0.
Добавьте на страницу еще четыре элемента типа TextBlock. Они являются надписями, помогающими пользователю определять данные, отображаемые на странице. Для установки свойств этих элементов управления воспользуйтесь значениями из табл. 25.2.
Таблица 25.2
Элемент управления | Свойство | Значение |
First Label | HorizontalAlignment | Left |
Margin | 330,190,0,0 | |
TextWrapping | Wrap | |
Text | ID | |
VerticalAlignment | Top | |
FontSize | 20 | |
Second Label | HorizontalAlignment | Left |
Margin | 460,190,0,0 | |
TextWrapping | Wrap | |
Text | Title | |
VerticalAlignment | Top | |
FontSize | 20 | |
Third Label | HorizontalAlignment | Left |
Margin | 620,190,0,0 | |
TextWrapping | Wrap | |
Text | First Name | |
VerticalAlignment | Top | |
FontSize | 20 | |
Fourth Label | HorizontalAlignment | Left |
Margin | 975,190,0,0 | |
TextWrapping | Wrap | |
Text | Last Name | |
VerticalAlignment | Top | |
FontSize | 20 |
Как и прежде, можно либо перетащить эти элементы управления из панели элементов и воспользоваться для установки их свойств окном Свойства, либо набрать в панели XAML следующую XAML-разметку, поместив ее после элемента управления типа TextBlock и перед закрывающим тегом </Grid>:
<TextBlock HorizontalAlignment="Left" Margin="330,190,0,0" TextWrapping="Wrap"
Text="ID" VerticalAlignment="Top" FontSize="20"/>
<TextBlock HorizontalAlignment="Left" Margin="460,190,0,0" TextWrapping="Wrap"
Text="Title" VerticalAlignment="Top" FontSize="20"/>
<TextBlock HorizontalAlignment="Left" Margin="620,190,0,0" TextWrapping="Wrap"
Text="First Name" VerticalAlignment="Top" FontSize="20"/>
<TextBlock HorizontalAlignment="Left" Margin="975,190,0,0" TextWrapping="Wrap"
Text="Last Name" VerticalAlignment="Top" FontSize="20"/>
Ниже элементов управления TextBlock добавьте три элемента управления типа TextBox, которые отображают текст идентификационного номера, имени и фамилии. Для установки значений этих элементов управления воспользуйтесь табл. 25.3. Обратите внимание на то, что для свойства Text должно быть установлено значение пустой строки (""). Также заметьте, что элемент управления id типа TextBox помечен как доступный только для чтения. Дело в том, что клиентские идентификационные номера (ID) станут генерироваться в коде, который будет добавлен чуть позже в автоматическом режиме.
Таблица 25.3
Элемент управления | Свойство | Значение |
First TextBox | x:Name | Id |
HorizontalAlignment | Left | |
Margin | 300,240,0,0 | |
TextWrapping | Wrap | |
Text | — | |
VerticalAlignment | Top | |
FontSize | 20 | |
IsReadOnly | True | |
Second TextBox | x:Name | firstName |
HorizontalAlignment | Left | |
Margin | 550,240,0,0 | |
TextWrapping | Wrap | |
Text | — | |
VerticalAlignment | Top | |
FontSize | 20 | |
Third TextBox | x:Name | lastName |
HorizontalAlignment | Left | |
Margin | 875,240,0,0 | |
TextWrapping | Wrap | |
Text | — | |
VerticalAlignment | Top | |
FontSize | 20 |
Эквивалентная XAML-разметка для этих элементов управления показана в следующем примере кода:
<TextBox x:Name="id" HorizontalAlignment="Left" Margin="300,240,0,0"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" FontSize="20"
IsReadOnly="True"/>
<TextBox x:Name="firstName" HorizontalAlignment="Left" Margin="550,240,0,0"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="300" FontSize="20"/>
<TextBox x:Name="lastName" HorizontalAlignment="Left" Margin="875,240,0,0"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="300" FontSize="20"/>
Свойство Name для элемента управления обязательным не является, но оно пригодится, если на этот элемент нужно будет сослаться в коде C# для приложения. Обратите внимание на то, что у свойства Name имеется префикс x:. Это ссылка на пространство имен XML , указанное в атрибутах страницы в верхней части XAML-разметки. Это пространство имен определяет свойство Name для всех элементов управления.
ПРИМЕЧАНИЕ Разбираться в том, почему свойство Name определено таким образом, совсем не обязательно, но для получения дополнительных сведений можно прочитать статью «x:Name Directive» по адресу .
В свойстве Width указывается ширина элемента управления, а в свойстве TextWrapping показано, что произойдет, если пользователь попытается ввести в элемент управления информацию, превышающую его ширину. В данном случае все элементы управления типа TextBox будут переносить текст на новую строку той же ширины (элемент управления увеличится по вертикали). Альтернативное значение, NoWrap, приведет к тому, что текст по мере ввода пользователем будет прокручиваться по горизонтали.
Добавьте к форме элемент управления типа ComboBox, поместив его ниже элемента управления Title типа TextBlock и расположив между элементами id и firstName типа TextBox. Установите для свойств этого элемента управления следующие значения (табл. 25.4).
Таблица 25.4
Свойство | Значение |
x:Name | Title |
HorizontalAlignment | Left |
Margin | 420,240,0,0 |
VerticalAlignment | Top |
Width | 100 |
FontSize | 20 |
Эквивалентная XAML-разметка для этого элемента управления имеет следующий вид:
<ComboBox x:Name="title" HorizontalAlignment="Left" Margin="420,240,0,0"
VerticalAlignment="Top" Width="100" FontSize="20"/>
Элемент управления типа ComboBox используется для отображения списка значений, из которых пользователь может выбрать нужные.
В окне конструктора щелкните на элементе управления ComboBox. Раскройте в окне Свойства категорию свойств Общие. Затем щелкните на кнопке с многоточием, появившейся рядом со свойством Items. Откроется окно Редактор коллекций "Object". Выберите в списке в левом нижнем углу окна элемент ComboBoxItem, а затем щелкните на кнопке Добавить. Раскройте в правой панели, отображающей свойства элемента, раздел Общие, а затем наберите в поле свойства Content строку Mr (рис. 25.5).
Рис. 25.5
Щелкните на кнопке OK. Редактор коллекций закроется. Если посмотреть на XAML-разметку для элемента title типа ComboBox, то в ней должен быть следующий код:
<ComboBox x:Name="title" HorizontalAlignment="Left" Margin="420,240,0,0"
VerticalAlignment="Top" Width="100" FontSize="20"/>
<ComboBoxItem Content="Mr"/>
</ComboBox>
Здесь следует отметить два обстоятельства. Первое заключается в том, что разметка ComboBox была разбита на открывающий тег <ComboBox> и закрывающий тег </ComboBox>. А второе заключается в том, что между этими тегами среда Visual Studio добавила элемент ComboBoxItem со свойством Content, для которого установлено значение Mr. Это значение при работе приложения будет показано в качестве элемента раскрывающегося списка.
Добавьте к элементу title типа ComboBox значения Mrs, Ms и Miss. Для этого можете либо воспользоваться редактором коллекций, либо набрать XAML-разметку вручную. Получившаяся в результате этого разметка должна иметь следующий вид:
<ComboBox x:Name="title" HorizontalAlignment="Left" Margin="420,240,0,0"
VerticalAlignment="Top" Width="75" FontSize="20">
<ComboBoxItem Content="Mr"/>
<ComboBoxItem Content="Mrs"/>
<ComboBoxItem Content="Ms"/>
<ComboBoxItem Content="Miss"/>
</ComboBox>
ПРИМЕЧАНИЕ Элемент управления типа ComboBox может выводить на экран простые элементы, такие как набор элементов управления типа ComboBoxItem, показывающих текст, но может выводить и более сложные элементы, такие как кнопки, флажки и переключатели. При добавлении простых элементов типа ComboBoxItem, наверное, будет проще набрать XAML-разметку вручную, но при добавлении более сложных элементов управления весьма полезным может оказаться редактор коллекций Object. Но особо изощряться в поле со списком не стоит. Самыми удачными получаются приложения, предоставляющие наиболее интуитивно понятные пользовательские интерфейсы, а вставка в поле со списком сложных элементов управления может только сбить пользователя с толку.
Добавьте к форме еще два элемента управления типа TextBox и еще два элемента управления типа TextBlock. Элементы управления TextBox позволят пользователю вводить адреса электронной почты и номера телефонов клиентов, а элементы управления TextBlock предоставят надписи для текстовых полей. Для установки свойств элементов управления воспользуйтесь значениями из табл. 25.5.
Таблица 25.5
Элемент управления | Свойство | Значение |
Первый TextBlock | HorizontalAlignment | Left |
Margin | 300,390,0,0 | |
TextWrapping | Wrap | |
Text | | |
VerticalAlignment | Top | |
FontSize | 20 | |
Первый TextBox | x:Name | |
HorizontalAlignment | Left | |
Margin | 450,390,0,0 | |
TextWrapping | Wrap | |
Text | Leave Empty | |
VerticalAlignment | Top | |
Width | 400 | |
FontSize | 20 | |
Второй TextBlock | HorizontalAlignment | Left |
Margin | 300,540,0,0 | |
TextWrapping | Wrap | |
Text | Phone | |
VerticalAlignment | Top | |
FontSize | 20 | |
Второй TextBox | x:Name | phone |
HorizontalAlignment | Left | |
Margin | 450,540,0,0 | |
TextWrapping | Wrap | |
Text | Leave Empty | |
VerticalAlignment | Top | |
Width | 200 | |
FontSize | 20 |
XAML-разметка для этих элементов управления должна иметь следующий вид:
<TextBlock HorizontalAlignment="Left" Margin="300,390,0,0" TextWrapping="Wrap"
Text="Email" VerticalAlignment="Top" FontSize="20"/>
<TextBox x:Name="email" HorizontalAlignment="Left" Margin="450,390,0,0"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="400" FontSize="20"/>
<TextBlock HorizontalAlignment="Left" Margin="300,540,0,0" TextWrapping="Wrap"
Text="Phone" VerticalAlignment="Top" FontSize="20"/>
<TextBox x:Name="phone" HorizontalAlignment="Left" Margin="450,540,0,0"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="200" FontSize="20"/>
Форма в окне конструктора должна выглядеть следующим образом (рис. 25.6).
Рис. 25.6
Щелкните в меню Отладка на пункте Начать отладку, чтобы инициировать сборку и запуск приложения.
Приложение будет запущено и выведет на экран форму, изображенную на рис. 25.7. Вы можете вводить в форму данные и выбирать из поля со списком вид
Рис. 25.7
обращения к клиенту, но пока это все, что вам доступно. Куда более серьезной проблемой является весьма неприглядный внешний вид формы. Правая сторона отображаемой формы получилась обрезанной, много текста было перенесено на новую строку, а текстовое поле Last Name оказалось усеченным.
Перетащите правую сторону окна, чтобы расширить область отображения и добиться вывода на экран текста и элементов управления в том виде, в котором они появлялись в окне конструктора среды Visual Studio. Это и будет оптимальным размером разработанной формы.
Сделайте ширину окна, отображающего приложение Customer, минимальной. Основная часть формы исчезнет. Часть содержимого элементов типа TextBlock будет отображена с переносом на новые строки, но форма в этом представлении станет совершенно бесполезной.
Вернитесь в среду Visual Studio и в меню Отладка щелкните на пункте Остановить отладку.
Рис. 25.8
Использование симулятора для тестирования приложений универсальной платформы Windows
Используя симулятор, предоставляемый средой Visual Studio 2015, вы можете протестировать свои UWP-приложения даже при отсутствии планшетного компьютера и увидеть, как они ведут себя на мобильном устройстве. Симулятор имитирует планшетное устройство, предоставляя возможность эмулировать такие жесты пользователя, как сведение и разведение пальцев на объектах и проведение пальцем по объекту, а также вращение и смену разрешения устройства.
Для запуска приложения в симуляторе откройте в панели инструментов Visual Studio раскрывающийся список целевого объекта отладки (Debug Target). Изначально в качестве целевого объекта отладки устанавливается Локальный компьютер, что заставляет приложение запускаться в полноэкранном режиме вашего компьютера, но в этом списке можно выбрать пункт Симулятор, запустив при отладке приложения симулятор. Заметьте, что вы также можете указать в качестве целевого объекта отладки другой компьютер на тот случай, если вам нужно выполнить удаленную отладку (при выборе этого варианта будет предложено ввести сетевой адрес удаленного компьютера). Список выбора целевого объекта отладки показан на рис. 25.9.
Рис. 25.9
После выбора варианта Симулятор при запуске приложения в Visual Studio из меню Отладка будет запущен симулятор, который выведет приложение на экран. Панель инструментов, расположенная с правой стороны окна симулятора, содержит подборку инструментов, позволяющих имитировать жесты пользователя с помощью мыши. Можно даже имитировать местоположение пользователя, если приложению требуется информация о географическом расположении устройства. Но для тестирования разметки приложения наиболее важными инструментами будут кнопки Повернуть по часовой стрелке на 90 градусов, Повернуть против часовой стрелки на 90 градусов и Изменить разрешение. На рис. 25.10 показано приложение Customers, запущенное в симуляторе. Приложение было раскрыто на весь экран. Надписи описывают функции всех кнопок симулятора.
Рис. 25.10
ПРИМЕЧАНИЕ Копии экрана, демонстрируемые в данном разделе, были сделаны на компьютере с симулятором, запущенным при разрешении 1366 × 768, представляющем дисплей с диагональю 10,6 дюйма. Чтобы получить точно такие же результаты при использовании другого разрешения экрана, может понадобиться щелкнуть на кнопке Изменение разрешения и переключиться на разрешение 1366 × 768.
На рис. 25.11 показано то же самое приложение после щелчка пользователя на кнопке Повернуть по часовой стрелке на 90 градусов, что заставило приложение выполняться в книжной ориентации.
Можно также попробовать посмотреть, как приложение поведет себя, если изменить разрешение симулятора. На рис. 25.12 показано приложение Customers, запущенное при установленном на симуляторе высоком разрешении (2560 х 1440, которое является обычным разрешением 27-дюймового монитора). Видно, что область отображения приложения втиснута в верхний левый угол экрана.
Рис. 25.11
Симулятор ведет себя точно так же, как компьютер, работающий под управлением Windows 10 (это, по сути, подключение к вашему компьютеру удаленного Рабочего стола). Чтобы остановить симулятор, щелкните на кнопке Windows (в симуляторе, а не на вашем Рабочем столе), а затем на пункте Выключение и на пункте Отключиться.
Рис. 25.12
Следует заметить, что среда Visual Studio поддерживает также эмуляторы для конкретных мобильных устройств. Некоторые из них могут быть перечислены в раскрывающемся списке симулятора, но вы сможете загружать новые эмуляторы, выбрав пункт загрузки новых эмуляторов.
Вы получили весьма поучительный урок, показывающий важность тщательной разметки приложения. Несмотря на то что приложение при запуске в окне того же размера, что и окно конструктора, имеет вполне приемлемый внешний вид, как только окно сужается, польза от приложения уменьшается или же оно становится абсолютно бесполезным. Кроме того, в приложении предполагается, что пользователь будет просматривать экран на устройстве с альбомной ориентацией. Если временно переключить окно конструктора на форм-фактор 12" Tablet и щелкнуть на кнопке ориентации Книжная, можно увидеть, что форма станет выглядеть так, будто пользователь запустил приложение на планшетном компьютере, поддерживающем различные варианты ориентации, и повернул устройство для переключения в книжный режим (рис. 25.8). (Не забудьте после этого переключить режим отображения обратно на форм-фактор 0" Desktop.)
Проблема в том, что рассмотренная на данный момент технология разметки не позволяет выполнять масштабирование и адаптироваться к различным форм-факторам и ориентации экрана. К счастью, для решения этой проблемы можно воспользоваться свойствами элемента управления Grid и еще одним функциональным средством, которое называется Диспетчером визуальных состояний.
Для реализации табличной разметки можно воспользоваться элементом управления Grid. В Grid содержатся строки и столбцы, и можно указать, в какие строки и столбцы должны быть помещены другие элементы управления. Привлекательность элемента управления Grid состоит в том, что вы можете указать размеры содержащихся в нем строк и столбцов в качестве относительных значений: по мере того как таблица сжимается или расширяется, адаптируясь под различные форм-факторы и ориентацию, на которые может переключиться пользователь, строки и столбцы могут сжиматься и расширяться пропорционально таблице. Пересечение строк и столбцов в таблице определяет ячейки, и если вы помещаете элементы управления в ячейки, то по мере сжатия или расширения строк и столбцов они будут перемещаться. Поэтому ключом к реализации масштабируемого пользовательского интерфейса является его разбиение на коллекцию ячеек и помещение связанных друг с другом элементов в одну и ту же ячейку. Ячейка может содержать еще одну таблицу, позволяя точно настроить позиционирование каждого элемента.
Если присмотреться к приложению Customers, можно заметить, что пользовательский интерфейс разбивается на две основные области: заголовок, содержащий название, и тело, содержащее подробные данные о клиенте. Как показано на следующей схеме (рис. 25.13), каждой из этих областей можно выделить относительные размеры с учетом некоторого промежутка между ними и отступа в нижней части формы.
На схеме показаны только начальные прикидки, где строка для заголовка вдвое выше строки-промежутка под ним. Строка для тела в 10 раз выше этого промежутка, а нижний отступ в два раза выше него.
Для хранения элементов в каждой области можно определить таблицу с четырьмя строками и поместить в каждую строку соответствующие элементы. Но как показано на рис. 25.14, тело формы может быть описано с помощью другой, более сложной таблицы.
Здесь опять высота каждой строки, как и ширина каждого столбца, указаны в относительных выражениях. Кроме того, совершенно очевидно, что TextBox-элементы для Email и Phone не вписываются в точности в эту табличную схему. Обладая достаточной степенью педантизма, можно выбрать вариант определения внутри тела формы дополнительных таблиц, чтобы поместить в них эти элементы. Но при этом нужно помнить о назначении данной таблицы, заключающемся в определении относительного позиционирования и создании промежутков между элементами. Поэтому выход элемента за границы ячейки табличной разметки вполне приемлем.
Рис. 25.13
Рис. 25.14
В следующем упражнении вам предстоит усовершенствовать разметку приложения Customers, воспользовавшись для позиционирования элементов управления этим табличным форматом.
Добавьте в существующий Grid-элемент в XAML-панели приложения Customers еще один элемент Grid. Задайте, как показано в следующем примере жирным шрифтом, для нового Grid-элемента отступы по 10 пикселов от левой и правой сторон родительского Grid-элемента и по 20 пикселов от его верхней и нижней сторон:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Margin="10,20,10,20">
</Grid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Adventure Works Customers" ... />
...
</Grid>
Строки и столбцы можно определить как часть существующего Grid-элемента, но чтобы по внешнему виду приложение ничем не отличалось от других UWP-приложений, нужно оставить в левой и верхней частях страницы немного пустого пространства.
Добавьте к новому Grid-элементу следующий <Grid.RowDefinitions>-раздел, показанный жирным шрифтом:
<Grid Margin="10,20,10,20">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
</Grid>
Раздел <Grid.RowDefinitions> определяет строки таблицы. В данном примере определены четыре строки. Можно указать размер строки в виде абсолютного значения в пикселах или же воспользоваться оператором *, показывающим, что размеры являются относительными и что Windows должна высчитать размеры строк самостоятельно при выполнении приложения в зависимости от форм-фактора и разрешения экрана. Значения, использованные в данном примере, соответствуют относительным размерам показанных на предыдущей схеме строк для заголовка, тела, разделяющего их пространства и нижнего отступа формы Customers.
Переместите в Grid элемент управления типа TextBlock, содержащий текст «Adventure Works Customers», поставив его сразу же после закрывающего тега </Grid.RowDefinitions>.
Добавьте к элементу управления TextBlock атрибут Grid.Row и установите для него значение 0.
Это укажет на необходимость позиционирования TextBlock внутри первой строки Grid. (В элементах управления Grid нумерация строк и столбцов начинается с нуля.)
ПРИМЕЧАНИЕ Атрибут Grid.Row является примером прикрепляемого свойства. Прикрепляемым называется свойство, которое элемент управления получает от элемента управления типа «контейнер», в котором он размещен. За пределами таблицы у TextBlock нет свойства Row (его наличие было бы бессмысленным), но при позиционировании внутри таблицы свойство Row прикрепляется к TextBlock и элемент управления TextBlock может присвоить ему значение. Затем элемент управления Grid использует это значение, чтобы определить, где нужно отобразить элемент управления TextBlock. Прикрепляемые свойства легко обнаружить, поскольку они имеют форму ТипКонтейнера.ИмяСвойства.
Удалите свойство Margin и установите для свойств HorizontalAlignment и VerticalAlignment значение Center. Это заставит TextBlock появляться в строке по центру.
XAML-разметка для элементов управления Grid и TextBlock должна приобрести следующий вид (изменения в TextBlock выделены жирным шрифтом):
<Grid Margin="10,20,10,20">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" TextWrapping="Wrap"
Text="Adventure Works Customers" VerticalAlignment="Center" FontSize="50"/>
...
</Grid>
Добавьте после элемента управления TextBlock еще одну вложенную таблицу в виде элемента управления Grid. Этот Grid-контейнер будет использоваться для разметки элементов управления внутри тела формы и должен появиться в третьей строке внешнего Grid-контейнера (с размером строки, указанным как 10*), поэтому, как показано далее жирным шрифтом, установите для свойства Grid.Row значение 2:
<Grid Margin="10,20,10,20">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" .../>
<Grid Grid.Row="2">
</Grid>
...
</Grid>
Добавьте к новому элементу управления Grid разделы <Grid.RowDefinitions> и <Grid.ColumnDefinitions>:
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="4*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
Эти определения строк и столбцов указывают высоту и ширину каждой строки и каждого столбца, показанных ранее на схеме, изображающей структуру тела формы. Между каждым столбцом, в котором будут содержаться элементы управления, имеется небольшое пространство в 20 пикселов.
Переместите элементы управления TextBlock, показывающие надписи ID, Title, Last Name и First Name, поместив их внутри вложенного элемента управления Grid сразу же после закрывающего тега </Grid.ColumnDefinitions>.
Установите для свойства Grid.Row каждого элемента управления TextBlock значение 0 (эти надписи будут появляться в первой строке таблицы). Установите для свойства Grid.Column надписи ID значение 1, для свойства Grid.Column надписи Title — значение 3, для свойства Grid.Column надписи First Name — значение 5 и для свойства Grid.Column надписи Last Name — значение 7.
Удалите свойство Margin из каждого элемента управления TextBlock и установите для их свойств HorizontalAlignment и VerticalAlignment значение Center. XAML-разметка для этих элементов управления должна получить следующий вид (все изменения выделены жирным шрифтом):
<Grid Grid.Row="2">
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="ID" VerticalAlignment="Center" FontSize="20"/>
TextBlock Grid.Row="0" Grid.Column="3" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Title" VerticalAlignment="Center" FontSize="20"/>
<TextBlock Grid.Row="0" Grid.Column="5" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="First Name" VerticalAlignment="Center" FontSize="20"/>
<TextBlock Grid.Row="0" Grid.Column="7" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Last Name" VerticalAlignment="Center" FontSize="20"/>
</Grid>
Переместите элементы управления типа TextBox с именами id, firstName и lastName, а также элемент управления типа ComboBox с именем title, поместив их внутри вложенного элемента управления Grid сразу же после элемента управления TextBlock с текстом Last Name.
Поместите эти элементы управления в строку 1 элемента управления Grid. Поместите элемент управления id в столбец 1, элемент управления title — в столбец 3, элемент управления firstName — в столбец 5, а элемент управления lastName — в столбец 7.
Удалите свойство Margin каждого из этих элементов управления и установите для свойства VerticalAlignment значение Center. Удалите свойство Width и установите для свойства HorizontalAlignment значение Stretch. Это заставит элементы управления занять при отображении всю ячейку, а также расширяться и сужаться при изменении размера ячейки.
Полный вид XAML-разметки для этих элементов управления с выделенными жирным шрифтом изменениями должен выглядеть следующим образом:
<Grid Grid.Row="2">
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
...
<TextBlock Grid.Row="0" Grid.Column="7" ... Text="Last Name" .../>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="id"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20" IsReadOnly="True"/>
<TextBox Grid.Row="1" Grid.Column="5" x:Name="firstName"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20"/>
<TextBox Grid.Row="1" Grid.Column="7" x:Name="lastName"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20"/>
<ComboBox Grid.Row="1" Grid.Column="3" x:Name="title"
HorizontalAlignment="Stretch" VerticalAlignment="Center" FontSize="20">
<ComboBoxItem Content="Mr"/>
<ComboBoxItem Content="Mrs"/>
<ComboBoxItem Content="Ms"/>
<ComboBoxItem Content="Miss"/>
</ComboBox>
</Grid>
Переместите элемент управления TextBlock для надписи Email и элемент управления TextBox по имени email во вложенный элемент управления Grid, поставив их сразу же после закрывающего тега элемента управления ComboBox по имени title. Поместите эти элементы управления в строку 3 элемента управления Grid. Поместите надпись Email в столбец 1, а элемент управления TextBox по имени email — в столбец 3. Кроме того, установите для свойства Grid.ColumnSpan элемента TextBox по имени email значение 5, чтобы, как показано на предыдущей схеме, элемент мог распространиться на значение, указанное в его свойстве Width через пять столбцов.
Установите для свойства HorizontalAlignment элемента управления надписи Email значение Center, а для свойства HorizontalAlignment элемента TextBox по имени email оставьте прежнее значение Left — этот элемент управления должен оставаться выровненным по левому краю относительно первого столбца, поверх которого он располагается, а не по центру относительно всех этих столбцов.
Установите для свойства VerticalAlignment надписи Email и элемента управления TextBox по имени email значение Center. Удалите для обоих этих элементов свойство Margin.
Полное определение этих элементов управления показано в следующей XAML-разметке:
<Grid Grid.Row="2">
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
...
<ComboBox Grid.Row="1" Grid.Column="3" x:Name="title" ...>
...
</ComboBox>
<TextBlock Grid.Row="3" Grid.Column="1" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Email" VerticalAlignment="Center" FontSize="20"/>
<TextBox Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="5" x:Name="email"
HorizontalAlignment="Left" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" Width="400" FontSize="20"/>
</Grid>
Переместите элемент управления TextBlock для надписи Phone и элемент управления TextBox по имени phone во вложенный элемент управления Grid и поставьте сразу же после элемента управления TextBox по имени email.
Поместите эти элементы управления в строку 5 элемента управления Grid. Поместите элемент управления с надписью Phone в столбец 1, а элемент управления TextBox по имени phone — в столбец 3. Установите для свойства Grid.ColumnSpan элемента управления TextBox по имени phone значение 3.
Установите для свойства HorizontalAlignment элемента управления с надписью Phone значение Center, а для свойства HorizontalAlignment элемента TextBox по имени phone оставьте значение Left.
Установите для свойства VerticalAlignment обоих элементов управления значение Center и удалите свойство Margin.
Полное определение этих элементов управления показано в следующей XAML-разметке:
<Grid Grid.Row="2">
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
...
<TextBox ... x:Name="email" .../>
<TextBlock Grid.Row="5" Grid.Column="1" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Phone" VerticalAlignment="Center" FontSize="20"/>
<TextBox Grid.Row="5" Grid.Column="3" Grid.ColumnSpan="3" x:Name="phone"
HorizontalAlignment="Left" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" Width="200" FontSize="20"/>
</Grid>
На панели инструментов Visual Studio выберите в раскрывающемся списке целевого объекта отладки пункт Симулятор. Приложение будет запущено в симуляторе, чтобы вы могли увидеть, как разметка адаптируется к различным разрешениям экрана и форм-факторам.
В меню Отладка щелкните на пункте Начать отладку. Симулятор начнет работу, и приложение Customers запустится. Раскройте окно приложения так, чтобы оно заняло весь экран симулятора. Щелкните на кнопке Изменить разрешение, а затем настройте симулятор на отображение приложения с использованием разрешения экрана 1366 × 768. Кроме того, убедитесь, что симулятор отображается в альбомной ориентации (если он отображается в книжной ориентации, щелкните на кнопке Повернуть по часовой стрелке на 90 градусов). Убедитесь в равномерном распределении элементов управления в этой ориентации.
Щелкните на кнопке Повернуть против часовой стрелки на 90 градусов, чтобы изменить ориентацию симулятора на книжную.
Приложение Customers должно подстроить разметку пользовательского интерфейса, и элементы управления должны быть по-прежнему равномерно распределены по форме и пригодны к работе (рис. 25.15).
Рис. 25.15
Щелкните на кнопке Повернуть против часовой стрелки на 90 градусов, чтобы вернуть симулятору альбомную ориентацию, а затем щелкните на кнопке Изменить разрешение и переключите разрешение симулятора на 2560 × 1400.
Заметьте, что элементы управления по-прежнему равномерно распределены по форме, хотя надписи, если только у вас нет экрана с диагональю 27 дюймов, могут читаться с большим трудом.
Еще раз щелкните на кнопке Изменить разрешение и переключите разрешение симулятора на 1024 × 768.
Еще раз обратите внимание на то, что расстояния между элементами и их размеры отрегулированы так, чтобы поддерживать равномерный баланс элементов пользовательского интерфейса (рис. 25.16).
Рис. 25.16
Еще раз щелкните на кнопке Изменить разрешение и опять переключите разрешение симулятора на 1366 × 768.
Дважды щелкните в симуляторе на верхнем крае формы, чтобы отображение вернулось в режим окна, а затем перетащите границу окна, изменив его размер так, чтобы форма отображалась в левой половине экрана. Уменьшите ширину окна до минимума. Таким приложение может появляться на смартфонах.
Все элементы управления остаются в поле зрения, но текст для надписи Phone и заголовок переносятся на новую строку, затрудняя чтение и усложняя тем самым использование элементов управления (рис. 25.17).
Рис. 25.17
Щелкните в симуляторе на кнопке Пуск (со значком Windows), затем на пункте Выключение и пункте Отключиться. Симулятор закроется, и вы вернетесь в среду Visual Studio.
На панели инструментов Visual Studio в раскрывающемся списке целевого объекта отладки выберите пункт Локальный компьютер.
Пользовательский интерфейс для приложения Customers масштабируется для различных разрешений экрана и форм-факторов, но его работа при уменьшении ширины области просмотра по-прежнему оставляет желать лучшего, и его внешний вид на смартфоне, ширина экрана которого еще меньше, теряет привлекательность. Если вдуматься, то решение проблемы в таком случае заключается по большому счету не в масштабировании элементов управления, а в другом способе их разметки. Например, было бы разумнее, если бы при узкой области просмотра у формы Customers был следующий внешний вид (рис. 25.18).
Рис. 25.18
Такого эффекта можно достичь несколькими способами.
• Можно создать несколько версий файла MainPage.xaml, по одной для каждого семейства устройств. Каждый из этих XAML-файлов может быть связан с одной и той же программной базой (MainPage.xaml.cs), чтобы все они запускали один и тот же код. Например, для создания XAML-файла для смартфона добавьте к проекту папку по имени DeviceFamily-Mobile (имя здесь будет играть важную роль), а затем добавьте в папку новое XAML-представление по имени MainPage.xaml, воспользовавшись командой меню Добавить новый элемент. Создайте в этой папке страницы разметку элементов управления, соответствующую их отображению на смартфоне. XAML-представление будет автоматически привязано к существующему файлу MainPage.xaml.cs. В ходе выполнения универсальная платформа Windows выберет подходящее представление на основе типа устройства, на котором запущено приложение.
• Можно воспользоваться Диспетчером визуальных состояний, изменяя с его помощью разметку страницы в ходе выполнения программы. Все UWP-приложения реализуют Диспетчер визуальных состояний, отслеживающий визуальное состояние приложения. Он может определить момент изменения высоты и ширины окна, и вы можете добавить XAML-разметку, позиционирующую элементы управления в зависимости от размера окна. Эта разметка может перемещать элементы или же делать их видимыми и невидимыми.
• Можно использовать Диспетчер визуальных состояний для переключения между представлениями на основе высоты и ширины экрана. Этот подход является сочетанием первых двух рассмотренных здесь вариантов, но в нем легче разобраться (для него не требуется большого объема хитроумного XAML-кода, вычисляющего наиболее подходящие места для каждого элемента управления), а также он наиболее гибок (будет работать, если уменьшить ширину окна на том же самом устройстве).
В следующих упражнениях вы станете придерживаться третьего из этих подходов. На первом этапе будет определена разметка для данных о клиенте, которые должны появляться при узкой области просмотра.
Добавьте в панели XAML для приложения Customers к элементу управления Grid свойства x:Name и Visibility, показанные далее жирным шрифтом:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="customersTabularView" Margin="10,20,10,20"
Visibility="Collapsed">
...
</Grid>
</Grid>
Этот элемент управления Grid будет содержать исходное представление формы. Позже на этот элемент управления Grid будут делаться ссылки в другой XAML-разметке из этого набора упражнений, поэтому нужно дать ему имя. Свойство Visibility указывает, виден этот элемент управления (Visible) или скрыт (Collapsed). Значением по умолчанию является Visible, но до некоторых пор, пока определяется другая таблица для отображения данных в формате столбцов, этот Grid будет скрыт.
Добавьте после закрывающего тега </Grid> для Grid-элемента customersTabularView еще один элемент управления Grid. Установите для его свойства x:Name значение customersColumnarView, для свойства Margin — значение 10,20,10,20, а для свойства Visibility — значение Visible.
СОВЕТ Щелкая на значках «+» и «–», появляющихся вдоль левого края XAML-разметки в панели XAML, принадлежащей окну конструктора, вы можете развернуть и свернуть элементы, упрощая тем самым чтение структуры.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="customersTabularView" Margin="10,20,10,20"
Visibility="Collapsed">
...
</Grid>
<Grid x:Name="customersColumnarView" Margin="10,20,10,20" Visibility="Visible">
</Grid>
</Grid>
Этот элемент управления Grid будет содержать «узкое» представление формы. Поля в этой таблице будут размечены по столбцам в соответствии с ранее рассмотренным описанием.
Добавьте в элемент управления Grid по имени customersColumnarView следующее определение строк:
<Grid x:Name="customersColumnarView" Margin="10,20,10,20" Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
</Grid>
Верхняя строка будет использоваться для вывода заголовка, а вторая, более крупная, — для вывода элементов управления, в которые пользователь будет вводить данные.
Добавьте сразу же после определения строк элемент управления TextBlock, показанный далее жирным шрифтом. Этот элемент показывает в первой строке Grid-элемента усеченный заголовок Customers. Установите для свойства FontSize значение 30:
<Grid x:Name="customersColumnarView" Margin="10,20,10,20" Visibility="Visible">
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" TextWrapping="Wrap"
Text="Customers" VerticalAlignment="Center" FontSize="30"/>
</Grid>
Добавьте к строке 1 Grid-элемента по имени customersColumnarView сразу же после элемента управления TextBlock, содержащего заголовок Customers, еще один элемент управления Grid. Этот Grid-элемент будет в двух столбцах отображать надписи и элементы управления для ввода данных, поэтому добавьте к нему определения строк и столбцов, показанные в следующем примере кода жирным шрифтом:
<TextBlock Grid.Row="0" ... />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
Обратите внимание на то, что если все строки или столбцы в наборе имеют одинаковую высоту или ширину, указывать их размеры не нужно.
После только что добавленного определения строк скопируйте в новый Grid-элемент XAML-разметку элементов управления типа TextBlock с названиями ID, Title, First Name и Last Name из Grid-элемента по имени customersTabularView. Поместите элемент управления для ID в строку 0, элемент управления для Title — в строку 1, элемент управления для First Name — в строку 2 и элемент управления для Last Name — в строку 3. Поместите все элементы управления в столбец 0:
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="ID" VerticalAlignment="Center" FontSize="20"/>
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Title" VerticalAlignment="Center" FontSize="20"/>
<TextBlock Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="First Name" VerticalAlignment="Center"
FontSize="20"/>
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Last Name" VerticalAlignment="Center"
FontSize="20"/>
Сразу же после элементов управления TextBox скопируйте в новый Grid-элемент XAML-разметку для элементов управления типа ComboBox и TextBox с именами id, title, firstName и lastName из Grid-элемента по имени customersTabularView. Поместите элемент id в строку 0, элемент title — в строку 1, элемент firstName — в строку 2 и элемент lastName — в строку 3. Поместите все четыре элемента управления в столбец 1. Также измените имена элементов управления, поставив префикс в виде буквы c (от слова column, означающего разметку по столбцам). Последнее изменение необходимо, чтобы избежать совпадения с именами существующих элементов управления в Grid-элементе по имени customersTabularView:
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Last Name" .../>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="cId"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20" IsReadOnly="True"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="cFirstName"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20"/>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="cLastName"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20"/>
<ComboBox Grid.Row="1" Grid.Column="1" x:Name="cTitle"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" FontSize="20">
<ComboBoxItem Content="Mr"/>
<ComboBoxItem Content="Mrs"/>
<ComboBoxItem Content="Ms"/>
<ComboBoxItem Content="Miss"/>
</ComboBox>
Скопируйте в новый Grid-элемент элементы управления типа TextBlock и TextBox для адреса электронной почты (email) и номера телефона из Grid-элемента по имени customersTabularView, поместив их после элемента управления типа ComboBox по имени cTitle. Поместите элементы управления типа TextBlock в столбец 0, в строки 4 и 5, а элементы управления типа TextBox — в столбец 1, в строки 4 и 5. Измените имя элемента email типа TextBox на cEmail и имя элемента phone типа TextBox — на cPhone. Удалите свойства Width у элементов cEmail и cPhone и установите для их свойств HorizontalAlignment значения Stretch:
<ComboBox ...>
...
</ComboBox>
<TextBlock Grid.Row="4" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Email" VerticalAlignment="Center" FontSize="20"/>
<TextBox Grid.Row="4" Grid.Column="1" x:Name="cEmail"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20"/>
<TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Center"
TextWrapping="Wrap" Text="Phone" VerticalAlignment="Center" FontSize="20"/>
<TextBox Grid.Row="5" Grid.Column="1" x:Name="cPhone"
HorizontalAlignment="Stretch" TextWrapping="Wrap" Text=""
VerticalAlignment="Center" FontSize="20"/>
В окне конструктора должна отобразиться примерно такая столбцовая разметка (рис. 25.19).
Рис. 25.19
Вернитесь к XAML-разметке для Grid-элемента по имени customersTabularView и установите для свойства Visibility значение Visible:
<Grid x:Name="customersTabularView" Margin="10,20,10,20" Visibility="Visible">
Для свойства Visibility в XAML-разметке Grid-элемента по имени customersColumnarView установите значение Collapsed:
<Grid x:Name="customersColumnarView" Margin="10,20,10,20" Visibility="Collapsed">
В окне конструктора должна отобразиться исходная табличная разметка формы Customers. Это исходное представление, которое будет использоваться приложением.
Теперь вы определили разметку, которая будет отображаться при узкой области просмотра. То, что все сделанное вами по сути является дублированием множества элементов управления и разметкой их в другой манере, не может не вызывать беспокойства. Если запустить форму и переключиться между представлениями, то как данные из одного представления будут перемещаться в другое представление? К примеру, если сведения о клиенте вводятся, когда приложение работает в полноэкранном режиме, а затем происходит переключение в режим узкой области просмотра, то заново отображаемые элементы управления не будут содержать те же самые данные, которые только что были введены. В UWP-приложениях эта проблема решается с помощью привязки данных. Это технология, с помощью которой можно связать один и тот же фрагмент данных с несколькими элементами управления, так что по мере изменения данных все элементы управления будут показывать обновленную информацию. Работа этой технологии будет показана в главе 26. А пока вы будете заниматься только приемами использования Диспетчера визуальных состояний для переключения между разметками при изменениях области просмотра.
Когда какое-нибудь свойство дисплея (например, высота или ширина) изменяется, вы можете воспользоваться инициаторами, подающими сигнал Диспетчеру визуальных состояний. Переходы визуального состояния, выполняемые этими инициаторами, можно определить в XAML-разметке вашего приложения. Именно этим вы и займетесь в следующем упражнении.
Добавьте в панели XAML приложения Customers после закрывающего тега </Grid>, принадлежащего Grid-элементу по имени customersColumnarView, следующую разметку:
<Grid x:Name="customersColumnarView" Margin="10,20,10,20" Visibility="Visible">
...
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="TabularLayout">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Переходы визуального состояния определяются путем реализации одной или нескольких групп визуального состояния. Каждая группа визуального состояния определяет переходы, которые должны произойти, когда Диспетчер визуальных состояний переключится в это состояние. Каждому состоянию должно быть дано значимое имя, помогающее определить его предназначение.
Добавьте к группе визуального состояния следующий инициатор (trigger), показанный жирным шрифтом:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="TabularLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="660"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Этот инициатор будет срабатывать, как только ширина окна станет меньше 660 пикселов. При этой ширине в форме Customers начинается перенос элементов управления и надписей на новую строку и с ними становится трудно работать.
Добавьте к XAML-разметке после определения инициатора следующий код, выделенный жирным шрифтом:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="TabularLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="660"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="customersTabularView.Visibility"
Value="Visible"/>
<Setter Target="customersColumnarView.Visibility"
Value="Collapsed"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Этот код определяет действия, производимые при срабатывании инициатора. В данном примере действия определяются с помощью элементов-установщиков Setter. Элемент Setter определяет устанавливаемое свойство и значение, которое для него должно быть установлено. Для данного представления команды Setter изменяют значения указанных свойств: Grid-элемент customersTabularView становится видимым, а Grid-элемент customersColumnarView скрывается (становится невидимым).
Добавьте после определения визуального состояния TabularLayout следующую разметку, показанную жирным шрифтом, которая определяет эквивалентные функциональные возможности для узкой области просмотра:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="TabularLayout">
...
</VisualState>
<VisualState x:Name="ColumnarLayout">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="customersTabularView.Visibility"
Value="Collapsed"/>
<Setter Target="customersColumnarView.Visibility"
Value="Visible"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Переход будет осуществляться, когда ширина окна станет меньше 660 пикселов. Приложение переключится в состояние ColumnarLayout: Grid-элемент customersTabularView скроется, а Grid-элемент customersColumnarView станет видимым.
В меню Отладка щелкните на пункте Начать отладку. Приложение запустится и отобразит полноэкранную форму Customers. Данные будут отображены с применением табличной разметки.
ПРИМЕЧАНИЕ Если вы используете дисплей с разрешением менее чем 1366 × 768, запускайте приложение в ранее рассмотренном симуляторе. Настройте симулятор на разрешение 1366 × 768.
Измените размер окна приложения Customer для отображения формы в узкой области просмотра. Когда ширина окна станет меньше 660 пикселов, отображение переключится на столбцовую разметку.
Измените размер окна приложения Customers, сделав его шире 660 пикселов (или переключите его в полноэкранный режим). Форма Customers опять перейдет к табличной разметке.
Вернитесь в среду Visual Studio и остановите отладку.
Следующим шагом после того, как будет решен вопрос с механикой основной разметки приложения, станет применение к пользовательскому интерфейсу стилей для добавления ему привлекательности. У элементов управления UWP-приложения имеются самые разнообразные свойства, которыми можно воспользоваться для изменения таких характеристик, как шрифт, цвет, размер, а также других атрибутов элемента. Значения этих свойств можно устанавливать отдельно для каждого элемента, но если одно и то же стилевое оформление нужно применить к нескольким элементам управления, такой подход может привести к утомительным и однообразным действиям. Кроме того, в лучших приложениях для пользовательского интерфейса выдерживается единообразие стиля, а при повторяющихся установках значений для одних и тех же свойств по мере добавления или удаления элементов управления сохранить его бывает нелегко. Зачастую приходится совершать однообразные действия, и при этом весьма высока вероятность хотя бы раз сделать что-нибудь не так!
Создавая UWP-приложения, можно определять многократно используемые стили. Их нужно реализовывать в виде общедоступных во всем приложении ресурсов, создав словарь ресурсов, и тогда они станут доступны всем элементам управления на всех страницах приложения. Можно также воспользоваться локальными ресурсами, применимыми только к одной странице, определив их в XAML-разметке для этой страницы. В следующем упражнении вы определите несколько простых стилей для приложения Customers, после чего они будут применены к элементам управления формы Customers.
В обозревателе решений щелкните правой кнопкой мыши на проекте Customers, укажите на пункт Добавить и щелкните на пункте Создать элемент.
В диалоговом окне Добавить новый элемент — Customers щелкните на пункте Словарь ресурсов. Наберите в поле Имя строку AppStyles.xaml, а затем щелкните на кнопке Добавить.
В окне редактора появится файл AppStyles.xaml. Словарь ресурсов является XAML-файлом, содержащим ресурсы, которыми может воспользоваться приложение. Файл AppStyles.xaml выглядит следующим образом:
<ResourceDictionary
xmlns=""
xmlns:x=""
xmlns:local="using:Customers">
</ResourceDictionary>
Стили являются одним из примеров ресурса, но вы можете также добавлять другие элементы. Фактически, первым ресурсом, который вы добавите, будет не стиль, а элемент ImageBrush (кисть), используемый для рисования фона самого внешнего элемента управления Grid, имеющегося в форме Customers.
В обозревателе решений щелкните правой кнопкой мыши на проекте Customers, укажите на пункт Добавить, а затем щелкните на пункте Создать папку. Измените имя новой папки на Images. Щелкните правой кнопкой мыши на папке Images, укажите на пункт Добавить и щелкните на пункте Существующий элемент.
В диалоговом окне Добавление существующего элемента — Customers перейдите в папку \Microsoft Press\VCSBS\Chapter 25\Resources folder вашей папки документов, щелкните на файле wood.jpg, а затем на пункте Добавить.
Файл wood.jpg добавляется к папке Images проекта Customers. Этот файл содержит изображение стильного фона, похожего на срез ствола дерева, который будет использован для формы Customers.
Выведите в окно редактора файл AppStyles.xaml и добавьте к нему следующую XAML-разметку, показанную жирным шрифтом:
<ResourceDictionary
xmlns=""
xmlns:x=""
xmlns:local="using:Customers">
<ImageBrush x:Key="WoodBrush" ImageSource="/books/26815/OEBPS/wood.jpg"/>
</ResourceDictionary>
Эта разметка создает ресурс типа ImageBrush по имени WoodBrush, основанный на файле wood.jpg. Этот ресурс можно использовать для установки фона элемента управления, и он выведет на экран изображение, находящееся в файле wood.jpg.
Добавьте к файлу AppStyles.xaml ниже ресурса ImageBrush следующий стиль, показанный жирным шрифтом:
<ResourceDictionary
...>
<ImageBrush x:Key="WoodBrush" ImageSource="/books/26815/OEBPS/wood.jpg"/>
<Style x:Key="GridStyle" TargetType="Grid">
<Setter Property="Background" Value="{StaticResource WoodBrush}"/>
</Style>
</ResourceDictionary>
Эта разметка показывает, как определить стиль. У элемента Style должно быть имя (ключ, позволяющий ссылаться на него из любого места приложения), и в нем должен определяться тип элемента управления, к которому может применяться стиль. Вы будете использовать этот стиль с элементом управления Grid.
Тело стиля состоит из одного или нескольких элементов Setter. В данном примере для свойства фона Background устанавливается значение ресурса WoodBrush, относящегося к типу ImageBrush. Но синтаксис выглядит немного странно. При указании значения свойства можно либо сослаться на одно из подходящих значений из тех, что определяются системой (например, Red, если нужно установить для фона насыщенный красный цвет), либо указать ресурс, который был где-либо определен. Для ссылки на определенный в каком-то месте ресурс используется ключевое слово StaticResource, а все выражение заключается в фигурные скобки.
Перед тем как получить возможность использовать этот стиль, требуется обновить словарь глобальных ресурсов для приложения, который находится в файле App.xaml, добавив ссылку на файл AppStyles.xaml. В обозревателе решений дважды щелкните на файле App.xaml, чтобы вывести его в окно редактора. Файл App.xaml имеет следующий вид:
<Application
x:Class="Customers.App"
xmlns=""
xmlns:x=""
xmlns:local="using:Customers"
RequestedTheme="Light">
</Application>
На данный момент в файле App.xaml определяется только объект приложения, и в область видимости вводятся несколько пространств имен, а словарь глобальных ресурсов пока что пуст.
Добавьте к файлу App.xaml код, выделенный жирным шрифтом:
<Application
x:Class="Customers.App"
xmlns=""
xmlns:x=""
xmlns:local="using:Customers"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="AppStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Эта разметка добавляет к списку ресурсов, доступных в глобальном словаре ресурсов, те ресурсы, которые определены в файле AppStyles.xaml. Теперь они доступны для использования по всему приложению.
Теперь переключитесь на файл MainPage.xaml для отображения пользовательского интерфейса, определенного в форме Customers. Найдите на панели XAML самый внешний элемент управления Grid:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
В XAML-разметке этого элемента управления замените свойство Background выделенным здесь жирным шрифтом свойством Style, которое ссылается на стиль GridStyle:
<Grid Style="{StaticResource GridStyle}">
Фон элемента управления Grid в окне конструктора должен переключиться и приобрести вид деревянной панели (рис. 25.20).
ПРИМЕЧАНИЕ В идеале нужно добиться того, чтобы любое фоновое изображение, применяемое к странице или элементу управления, сохраняло эстетическую привлекательность при изменении форм-фактора или ориентации устройства. Изображение, которое хорошо смотрится на 30-дюймовом мониторе, на смартфоне Windows может быть искажено и сжато. Возможно, для разных представлений и ориентации придется предоставлять альтернативные изображения и использовать Диспетчер визуальных состояний для внесения изменений в свойство Background элемента управления с целью переключения с одного изображения на другое по мере изменения визуального состояния.
Рис. 25.20
Вернитесь в окне редактора к файлу AppStyles.xaml и добавьте после стиля GridStyle стиль FontStyle:
<Style x:Key="GridStyle" TargetType="Grid">
...
</Style>
<Style x:Key="FontStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe Print"/>
</Style>
Этот стиль применяется к элементам типа TextBlock и изменяет шрифт на Segoe Print. Данные, выведенные этим шрифтом, напоминают рукописный текст.
На данном этапе вполне возможно дать ссылку на стиль FontStyle в каждом элементе управления TextBlock, которому требуется этот шрифт, но такой подход не даст никаких преимуществ над простой непосредственной установкой FontFamily в разметке для каждого элемента управления. Реальная эффективность стилей проявляется при сочетании сразу нескольких свойств, в чем вы убедитесь, выполняя следующие действия.
Добавьте к файлу AppStyles.xaml выделенный жирным шрифтом стиль HeaderStyle:
<Style x:Key="FontStyle"
TargetType="TextBlock">
...
</Style>
<Style x:Key="HeaderStyle" TargetType="TextBlock" BasedOn="{StaticResource
FontStyle}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="SteelBlue"/>
</Style>
Это составной стиль, устанавливающий для элементов управления типа TextBlock свойства HorizontalAlignment, TextWrapping, VerticalAlignment и Foreground. Кроме того, с помощью свойства BasedOn стиль HeaderStyle ссылается на стиль FontStyle. Свойство BasedOn предоставляет для стилей простую форму наследования.
Этот стиль будет использоваться для форматирования надписей, появляющихся в верхней части элементов управления customersTabularView и customersColumnarView. Но у этих заголовков разные размеры шрифта (заголовок для табличной разметки больше заголовка для столбцовой разметки), поэтому вы создадите еще два стиля, расширяющих стиль HeaderStyle.
Добавьте к файлу AppStyles.xaml следующие стили:
<Style x:Key="HeaderStyle" TargetType="TextBlock" BasedOn="{StaticResource
FontStyle}">
...
</Style>
<Style x:Key="TabularHeaderStyle" TargetType="TextBlock"
BasedOn="{StaticResource HeaderStyle}">
<Setter Property="FontSize" Value="40"/>
</Style>
<Style x:Key="ColumnarHeaderStyle" TargetType="TextBlock"
BasedOn="{StaticResource HeaderStyle}">
<Setter Property="FontSize" Value="30"/>
</Style>
Заметьте, что размеры шрифта для этих стилей немного меньше размеров шрифта, используемых для заголовков в элементах управления Grid на данный момент. Дело в том, что шрифт Segoe Print крупнее шрифта, используемого по умолчанию.
Вернитесь к файлу MainPage.xaml и найдите XAML-разметку для элемента управления типа TextBlock с надписью Adventure Works Customers в Grid-элементе customersTabularView:
<TextBlock Grid.Row="0" HorizontalAlignment="Center" TextWrapping="Wrap"
Text="Adventure Works Customers" VerticalAlignment="Center" FontSize="50"/>
Измените свойства этого элемента управления, указав в них ссылку на стиль TabularHeaderStyle, выделенную жирным шрифтом:
<TextBlock Grid.Row="0" Style="{StaticResource TabularHeaderStyle}"
Text="Adventure Works Customers"/>
У заголовка, отображаемого в окне конструктора, должны измениться цвет, размер и шрифт, и он должен приобрести следующий вид (рис. 25.21).
Рис. 25.21
Найдите в Grid-элементе customersColumnarView XAML-разметку для элемента управления типа TextBlock с надписью Customers:
<TextBlock Grid.Row="0" HorizontalAlignment="Center" TextWrapping="Wrap"
Text="Customers" VerticalAlignment="Center" FontSize="30"/>
Измените разметку этого элемента управления, указав в ней ссылку на стиль ColumnarHeaderStyle, выделенную жирным шрифтом:
<TextBlock Grid.Row="0" Style="{StaticResource ColumnarHeaderStyle}"
Text="Customers"/>
Но в окне конструктора это изменение не отобразится, поскольку по умолчанию Grid-элемент customersColumnarView скрыт. Тем не менее результат изменения проявится в этом упражнении при последующем запуске приложения.
Вернитесь в окне редактора к файлу AppStyles.xaml. Измените стиль HeaderStyle, добавив к нему дополнительные элементы установки свойств Setter, выделенные жирным шрифтом:
<Style x:Key="HeaderStyle" TargetType="TextBlock" BasedOn="{StaticResource
FontStyle}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="SteelBlue"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform">
<Setter.Value>
<CompositeTransform Rotation="-5"/>
</Setter.Value>
</Setter>
</Style>
Эти элементы с помощью преобразования поворачивают текст, отображаемый в заголовке, вокруг его центра на 5°.
ПРИМЕЧАНИЕ В этом примере показано простое преобразование. Применяя свойство RenderTransform, можно выполнять множество других разнообразных преобразований элемента, сочетая при этом сразу несколько преобразований. Например, можно переместить элемент по осям x и y, придать элементу наклон и задать ему новый масштаб.
Следует также отметить, что значением свойства RenderTransform является еще одна пара «свойство–значение» (свойство в ней Rotation, а значение –5). В подобных случаях значение указывается с использованием тега <Setter.Value>.
Перейдите к файлу MainPage.xaml. Теперь в окне конструктора заголовок должен отображаться как бы немного набекрень (рис. 25.22).
Рис. 25.22
Добавьте к файлу AppStyles.xaml следующий стиль:
<Style x:Key="LabelStyle" TargetType="TextBlock" BasedOn="{StaticResource
FontStyle}">
<Setter Property="FontSize" Value="30"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="AntiqueWhite"/>
</Style>
Этот стиль будет применяться к элементам типа TextBlock, предоставляющим надписи для различных элементов типа TextBox и ComboBox, используемых пользователями для ввода информации о клиентах. В стиле имеется ссылка на тот же самый стиль шрифта, что и для заголовков, но установлены другие, более подходящие для надписей значения свойств.
Вернитесь к файлу MainPage.xaml. Измените в панели XAML разметку для элементов управления типа TextBlock для каждой надписи в Grid-элементах customersTabularView и customersColumnarView. Удалите свойства HorizontalAlignment, TextWrapping, VerticalAlignment и FontSize и укажите ссылку на стиль LabelStyle, выделенную далее жирным шрифтом:
<Grid x:Name="customersTabularView" Margin="10,20,10,20" Visibility="Visible">
...
<Grid Grid.Row="2">
...
<TextBlock Grid.Row="0" Grid.Column="1" Style="{StaticResource
LabelStyle}" Text="ID"/>
<TextBlock Grid.Row="0" Grid.Column="3" Style="{StaticResource
LabelStyle}" Text="Title"/>
<TextBlock Grid.Row="0" Grid.Column="5" Style="{StaticResource
LabelStyle}" Text="First Name"/>
<TextBlock Grid.Row="0" Grid.Column="7" Style="{StaticResource
LabelStyle}" Text="Last Name"/>
...
<TextBlock Grid.Row="3" Grid.Column="1" Style="{StaticResource
LabelStyle}" Text="Email"/>
...
<TextBlock Grid.Row="5" Grid.Column="1" Style="{StaticResource
LabelStyle}" Text="Phone"/>
...
</Grid>
</Grid>
<Grid x:Name="customersColumnarView" Margin="10,20,10,20" Visibility="Collapsed">
...
<Grid Grid.Row="1">
...
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource
LabelStyle}" Text="ID"/>
<TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource
LabelStyle}" Text="Title"/>
<TextBlock Grid.Row="2" Grid.Column="0" Style="{StaticResource
LabelStyle}" Text="First Name"/>
<TextBlock Grid.Row="3" Grid.Column="0" Style="{StaticResource
LabelStyle}" Text="Last Name"/>
...
<TextBlock Grid.Row="4" Grid.Column="0" Style="{StaticResource
LabelStyle}" Text="Email"/>
...
<TextBlock Grid.Row="5" Grid.Column="0" Style="{StaticResource
LabelStyle}" Text="Phone"/>
...
</Grid>
</Grid>
Надписи в форме должны измениться: теперь они выведены шрифтом Segoe Print, белого цвета, размер 30 пунктов (рис. 25.23).
Щелкните в меню Отладка на пункте Начать отладку, инициируя сборку и запуск приложения.
Рис. 25.23
ПРИМЕЧАНИЕ Если запуск приложения осуществляется на дисплее с разрешением менее 1366 × 768, воспользуйтесь симулятором.
Должна появиться форма Customers, имеющая точно такое же стилевое оформление, как и в окне конструктора в среде Visual Studio. Заметьте, что при вводе в различные поля формы любого текста для элементов управления типа TextBox будут применяться шрифт и стиль, используемые по умолчанию.
ПРИМЕЧАНИЕ Шрифт Segoe Print больше подходит для названий и надписей и не рекомендуется в качестве шрифта для полей ввода данных, потому что некоторые символы в нем практически неотличимы друг от друга. Например, буква «l» в нижнем регистре очень похожа на цифру 1, а буква «O» в верхнем регистре мало чем отличается от цифры 0. Поэтому есть смысл оставить для элементов управления типа TextBox шрифт, используемый по умолчанию.
Измените размер окна, уменьшив его ширину, и убедитесь в том, что к элементам управления применяется стилевое оформление, определенное в Grid-элементе customersColumnarView. Форма должна приобрести следующий вид (рис. 25.24).
Вернитесь в среду Visual Studio и остановите отладку.
Чтобы вы могли получить полное представление, на рис. 25.25 показано приложение Customers, запущенное на эмуляторе устройства, работающего под управлением операционной системы Windows Phone 10.
Рис. 25.24
У вас есть возможность убедиться в том, что использование стилей позволяет легко и просто реализовывать ряд весьма впечатляющих эффектов. Кроме того, аккуратное использование стилей облегчает сопровождение кода по сравнению с тем, каким бы оно было, если бы значения для свойств устанавливались в отдельно взятых элементах управления. К примеру, если в приложении Customers вам понадобится переключить шрифт, используемый для надписей и заголовков, придется всего лишь внести небольшое изменение в стиль FontStyle. В принципе, стили нужно использовать везде, где только можно, поскольку это не только облегчает сопровождение кода, но и помогает поддерживать чистоту и лаконичность XAML-разметки для форм, в которой нужно будет указывать только элементы управления и их расположение, а не то, как именно они должны выглядеть в форме. Для определения сложных стилей, встраиваемых в приложения, можно также воспользоваться средством Microsoft Blend для среды
Рис. 25.25
Visual Studio 2015. Профессиональные художники-графики могут применять Blend для разработки оригинальных стилей и предоставлять их в форме XAML-разметок разработчикам, создающим приложения. Разработчику для ссылки на нужные стили останется всего лишь добавить соответствующие теги Style к элементам пользовательского интерфейса.
В этой главе вы узнали, как для реализации пользовательского интерфейса используются элементы управления Grid, позволяющие выполнять масштабирование под различные форм-факторы и ориентацию устройств. Вы также научились использовать Диспетчер визуальных состояний для адаптации разметки элементов управления при изменении пользователем размеров окна, в котором отображается приложение. И наконец, вы узнали, как создаются оригинальные стили и как они применяются к элементам управления формы. Следующей задачей после того, как вы определили пользовательский интерфейс, станет добавление к приложению функциональных средств, позволяющих пользователю выводить на экран данные и изменять их. Ее решению и будут посвящены заключительные главы книги.
Если хотите продолжить работу и изучить следующую главу, оставьте открытой среду Visual Studio 2015 и переходите к главе 26.
Если сейчас вы хотите выйти из среды Visual Studio 2015, то в меню Файл щелкните на пункте Выход. Увидев диалоговое окно с предложением сохранить изменения, щелкните на кнопке Да и сохраните проект.
Чтобы | Сделайте следующее |
Создать новое UWP-приложение | Воспользуйтесь одним из UWP-шаблонов, имеющихся в среде Visual Studio 2015, например шаблоном пустого приложения |
Реализовать пользовательский интерфейс, способный масштабироваться под различные форм-факторы и ориентацию устройств | Воспользуйтесь элементом управления Grid. Разбейте Grid-элемент на строки и столбцы и вместо указания для элементов управления абсолютного местоположения относительно сторон Grid-элемента поместите их в эти строки и столбцы |
Реализовать пользовательский интерфейс, способный подстраиваться под различные значения ширины дисплея | Создайте разные разметки для каждого представления, отображающие элементы управления подобающим образом. Для выбора разметки, отображаемой при изменении визуального состояния, воспользуйтесь Диспетчером визуальных состояний |
Создать оригинальные стили | Добавьте к приложению словарь ресурсов. Определите в этом словаре стили, воспользовавшись элементом <Style>, и укажите свойства, изменяемые каждым стилем, например: <Style x:Key="GridStyle" TargetType="Grid"> <Setter Property="Background" Value="{StaticResource WoodBrush}"/> </Style> |
Применить к элементу управления оригинальный стиль | Установите для элемента управления свойство Style и сошлитесь на стиль по имени, например: <Grid Style="{StaticResource GridStyle}"> |