Главная » C#, Windows Runtime, XAML, Разработка для Windows 8 » Построение базовых интерфейсов XAML

0

Немного о XAML

Независимо от того, используете Вы C# или С++ для разработки своих Windows 8 приложений, Вы будете использовать XAML, с помощью которого в приложении описывается большинство интерфейсных элементов, стилей и ресурсов.

XAML    (eXtensible    Application    Markup    Language)    представляет     собой декларативный язык, построенный на базе XML. Основное  назначение этого языка состоит в описании интерфейса приложения.  XAML может быть знаком разработчикам по  таким  технологиям,  как  Windows Presentation Foundation и  Silverlight. XAML  также  применяется в  Workflow  Foundation для  описания рабочих процессов.

Чтобы лучше понять назначение XAML, достаточно вспомнить, как создавались интерфейсы на языке программирования C# при использовании Windows Forms. Так,  кусок  кода,  создающий  небольшую  кнопку,  мог  выглядеть  следующим образом:

this.myButton = new System.Windows.Forms.Button(); this.myButton.Location = new System.Drawing.Point(120, 60);

this.myButton.Name = "myButton";

this.myButton.Size = new System.Drawing.Size(110, 40); this.myButton.Text = "Hello";

this.Controls.Add(this.myButton);

С одной стороны, приведенный выше код является громоздким, а с  другой, он не дает понимания того, как устроен интерфейс. Очень сложно проследить зависимости между контейнерами и понять структуру интерфейса. Кроме того, если Вы сталкивались с визуальным дизайнером приложений WinForms, то знаете, что код, сгенерированный дизайнером, лучше не модифицировать. Во-первых, дизайнер может его просто не распознать, а во-вторых, все «ручные» изменения могут быть удалены при любой модификации интерфейса. Это связано с тем, что разобрать и обработать код, написанный на C#, достаточно сложно. Кроме того, код может содержать вставки, не связанные с построением интерфейса.

Рассмотрим аналогичный код на XAML:

<Canvas x:Name="LayoutRoot">

<Button Content="Hello" Canvas.Top="60" Canvas.Left="120" Width="110" Height="40" x:Name="myButton"></Button>

</Canvas>

Как видно, XAML является более интуитивным, чем код на C#, не  только для разработчиков,  но  и  для  других  членов  команды,   например  дизайнеров. Это  позволяет  использовать  XAML  для   создания  прототипов  интерфейсов и переводить их на стадию разработки, используя один и тот же код.

По коду XAML легко определить все параметры нашей кнопки и ее положение в  общей иерархии интерфейсных объектов, а  также  очень легко построить дерево объектов.

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

А сейчас перейдем к изучению синтаксиса XAML.

Основные конструкции

Если Вы владеете XML, то изучение XAML для Вас не составит  особого труда. Как и в XML, любой элемент представлен тегом, который может иметь атрибуты и дочерние элементы. Атрибуты перечисляются в теге элемента со значениями в виде текстовых строк, а дочерние  элементы задаются между открывающим и закрывающим тегами основного элемента:

<Canvas Name="LayoutRoot">

<Button Content="Hello" Canvas.Top="60" Canvas.Left="120" Width="110" Height="40" Name="button1"></Button>

</Canvas>

Код выше описывает элемент Canvas с одним атрибутом и одним  дочерним элементом (Button). В основном теге Button установлено шесть атрибутов и ни одного дочернего элемента. Как и в XML, тег Button можно было бы записать следующим образом (явное отсутствие закрывающего тега):

<Button Content="Hello" Canvas.Top="60" Canvas.Left="120" Width="110" Height="40" Name="button1" />

XAML (как и XML) чувствителен к регистру символов. При этом регистр имеет значение  для  описания  не  только  элементов  и  атрибутов,  но  и  значений атрибутов. Так, код ниже создает два объекта с именами Button1 и button1:

<Button Content="Hello" Canvas.Top="60" Canvas.Left="120" Width="110" Height="40" Name="button1" />

<Button Content="Hello" Canvas.Top="160" Canvas.Left="120" Width="110" Height="40" Name="Button1" />

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

Блок 1

<Button Content="Hello" Canvas.Top="60" Canvas.Left="120" Width="110" Height="40" Name="button1"></Button>

Блок 2

<Button Content="Hello" Canvas.Top="60" Canvas.Left="120" Name="button1">

<Button.Width> 110

</Button.Width>

<Button.Height> 40

</Button.Height>

</Button>

При этом через атрибуты можно не  только задавать простые  значения, но и создавать более сложные объекты. Рассмотрим следующие два блока кода:

Блок 1

<Rectangle Width="100" Height="50" Fill="Red"></Rectangle>

Блок 2

<Rectangle Width="100" Height="50">

<Rectangle.Fill>

<SolidColorBrush Color="Red" />

</Rectangle.Fill>

</Rectangle>

Первый блок кода имеет более простую запись, но, как и во втором блоке, для установки значения свойства Fill создается кисть SolidColorBrush. Второй блок также не идеален, ведь тут с помощью  атрибута создается объект типа Color, который также можно расписать через набор дочерних элементов.

Создание  объектов  через   атрибуты  возможно  с   помощью   специальных конверторов. На самом деле, даже при простой  установке значения свойства Width работает конвертор. Ведь Width  является целочисленным свойством, а мы присваиваем ему текст.

Если  конвертора  не  хватает,  то  его  следует  дописать  самостоятельно.  Если посмотреть на шаблон Blank проекта  приложения в стиле Metro, то можно заметить, что там предлагается следующий код:

public sealed class BooleanToVisibilityConverter : IValueConverter

{

public object Convert(object value, Type targetType, object parameter, string language)

{

return (value is bool && (bool)value) ?

Visibility.Visible : Visibility.Collapsed;

}

public object ConvertBack(object value, Type targetType, object parameter, string language)

{

return value is Visibility && (Visibility)value == Visibility.Visible;

}

}

Тут  описан  конвертор,  который  позволяет  выполнить  преобразование  для одного  из  основных  свойств  всех  элементов  управления  —  Visibility.  Это свойство  принимает  значение  перечислимого  типа  Visibility:  Collapsed  или Visible. С помощью  нашего конвертора можно установить свойству значение переменной типа bool. Такой подход позволяет упростить работу с данными при связывании. Как использовать конверторы, рассмотрим позже.

Рассмотрим два эквивалентных блока кода:

Блок 1

<TextBlock> Hello

</TextBlock>

Блок 2

<TextBlock Text="Hello"></TextBlock>

Как видно, в первом блоке свойство Text элемента TextBlock задается неявно. Такой подход реализован для простоты (вспомните, например, синтаксис HTML) использования XAML. Любой класс, описывающий  элемент, может содержать лишь одно такое свойство (контентное свойство), которое задается с помощью атрибута ContentPropertyAttribute при описании класса.

Последним вопросом, который мы рассмотрим в этом разделе, является создание коллекций. Рассмотрим следующий блок кода:

<Rectangle Width="100" Height="50">

<Rectangle.Fill>

<LinearGradientBrush>

<LinearGradientBrush.GradientStops>

<GradientStopCollection>

<GradientStop Offset="0.0" Color="Red" />

<GradientStop Offset="1.0" Color="Green" />

</GradientStopCollection>

</LinearGradientBrush.GradientStops>

</LinearGradientBrush>

</Rectangle.Fill>

</Rectangle>

Этот код задает градиентную заливку для прямоугольника. Первое, что бросается в глаза, — это невозможность задать градиентную заливку через атрибуты. Ведь тут требуется создать целую коллекцию  объектов, каждый из которых имеет большое количество свойств. Между тем, и этот синтаксис можно сократить.

Первое, на что нужно обратить внимание, это то, что свойство GradientStops является контентным, а значит, его можно не писать. Тогда весь контент внутри LinearGradientBrush будет ассоциироваться именно с GradientStops:

<Rectangle Width="100" Height="50">

<Rectangle.Fill>

<LinearGradientBrush>

<GradientStopCollection>

<GradientStop Offset="0.0" Color="Red" />

<GradientStop Offset="1.0" Color="Green" />

</GradientStopCollection>

</LinearGradientBrush>

</Rectangle.Fill>

</Rectangle>

Кроме того, анализатор XAML достаточно «сообразительный», чтобы распознать тип свойства GradientStops и приготовиться к созданию  коллекции объектов. Поэтому тип коллекции явно задавать не нужно. Таким образом, наш код стал еще меньше:

<Rectangle Width="100" Height="50">

<Rectangle.Fill>

<LinearGradientBrush>

<GradientStop Offset="0.0" Color="Red" />

<GradientStop Offset="1.0" Color="Green" />

</LinearGradientBrush>

</Rectangle.Fill>

</Rectangle>

Между тем, несмотря на одинаковый результат, первоначальный код и последний блок выполняются по-разному. Так, если Вы явно  указываете коллекцию, то при запуске приложения сначала генерируется объект типа коллекции, а затем создаются элементы,  которые помещаются в созданный объект, а сам объект присваивается свойству (в данном случае, Fill). Это позволяет задать не только коллекцию элементов, но и имя самой коллекции, и обращаться к ней в коде. Но, используя такой подход, следует помнить, что многие коллекции не могут быть созданы явно. Их создание  скрыто внутри дочернего элемента, и анализатор XAML просто вызывает метод Add без явного создания объекта типа коллекции. Поэтому  синтаксис  с  явной  записью  типа  коллекции  очень  часто   просто невозможен. Например, следующий код не будет работать,  поскольку создать явно объект типа UIElementCollection невозможно:

<StackPanel x:Name="LayoutRoot" Background="White">

<StackPanel.Children>

<UIElementCollection>

<Button Width="100" Height="50"></Button>

</UIElementCollection>

</StackPanel.Children>

</StackPanel>

А вот следующие два блока будут работать замечательно:

Блок 1

<StackPanel x:Name="LayoutRoot" Background="White">

<StackPanel.Children>

<Button Width="100" Height="50"></Button>

</StackPanel.Children>

</StackPanel>

Блок 2 (Children – контентный элемент)

<StackPanel x:Name="LayoutRoot" Background="White">

<Button Width="100" Height="50"></Button>

</StackPanel>

Сергей Лутай, Сергей Байдачный, Windows 8 для C# разработчиков

По теме:

  • Комментарии