Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Windows Presentation Foundation.docx
Скачиваний:
43
Добавлен:
02.11.2018
Размер:
1.15 Mб
Скачать

2. ПРостейшее Приложение wpf

Следующий листинг описывает простейшее приложение WPF, включающее единственное окно интерфейса:

// файл program.cs

using System;

using System.Windows;

class Program

{

[STAThread]

static void Main()

{

Window myWin = new Window();

myWin.Title = "First Program";

myWin.Content = "Hello, world";

Application myApp = new Application();

myApp.Run(myWin);

}

}

Проанализируем данный код. Пространство имён System.Windows содержит классы Window и Application, описывающее окно и приложение соответственно. Точка входа помечена атрибутом [STAThread]. Это является обязательным условием для любого приложения WPF и связано с моделью многопоточности, применяемой в WPF. В методе Main() создаётся и настраивается объект окна, затем создаётся объект приложения. Вызов myApp.Run(myWin) приводит к отображению окна myWin и запуску цикл обработки событий.

Скомпилируем программу при помощи компилятора командной строки:

csc.exe /r:PresentationCore.dll;PresentationFramework.dll;WindowsBase.dll

/t:winexe program.cs

При помощи ключа /r устанавливаются ссылки на сборки PresentationFramework.dll, PresentationCore.dll и WindowsBase.dll с классами WPF. Ключ /t:winexe указывает, что создаётся оконное приложение.

Отметим, что наше приложение допускает другую организацию. Вместо настройки объекта Window можно создать наследник этого класс и выполнить установку параметров в конструкторе наследника или в специальном методе:

// наследник класса Window, описывающий пользовательское окно

class MyWindow : Window

{

public MyWindow()

{

Title = "First Program";

Content = "Hello, world";

}

}

В Visual Studio приложениям WPF соответствует отдельный шаблон проекта. Этот шаблон ориентирован на использование XAML, поэтому в случае однооконного приложения Visual Studio создаст следующий набор файлов:

  • файлы Window1.xaml.cs и Window1.xaml (на языке XAML) описывают класс Window1, являющийся наследником класса Window;

  • файлы App.xaml.cs и App.xaml описывают класс App – наследник класса Application.

Ниже приведён файл Window1.xaml для простейшего окна:

<Window x:Class="WpfApplication.Window1"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="First Program" Height="300" Width="300">

Hello, world

</Window>

Visual Studio выполняет компиляцию проекта WPF в два этапа. Вначале для каждого файла XAML генерируется два файла, сохраняемых в подкаталогах obj\Debug или obj\Release (в зависимости от цели компиляции):

  • файл с расширением *.baml – двоичное представление XAML-файла, внедряемое в сборку в виде ресурса (BAML-файл);

  • файл с расширением *.g.cs – разделяемый класс, который соответствует XAML-описанию. Этот класс включает поля для всех именованных элементов файла XAML и реализацию метода InitializeComponent(), загружающего BAML-данные из ресурсов сборки. Кроме этого, класс содержит метод, подключающий все обработчики событий.

На втором этапе сгенерированные файлы компилируются вместе с исходными файлами C# в единую сборку (рис. 2).

Рис. 2. Компиляция WPF-приложения в Visual Studio.

3. XAML

XAML (Extensible Application Markup Language, расширяемый язык разметки приложений) – это язык разметки, предлагающий основанный на XML синтаксис для представления логического дерева объектов .NET.

Существует несколько подмножеств XAML:

  • WPF XAML включает элементы, описывающие содержимое WPF вроде векторной графики и элементов управления;

  • XPS XAML – часть WPF XAML, определяющая XML-представление форматированных электронных документов. Эта часть опубликована как отдельный стандарт XML Paper Specification (XPS);

  • Silverlight XAML – подмножество WPF XAML, предназначенное для Silverlight-приложений. Silverlight – это межплатформенный браузерный подключаемый модуль, позволяющий создавать веб-содержимое с двумерной графикой, анимацией, аудио и видео;

  • WF XAML включает элементы, описывающие содержимое Windows Workflow Foundation.

Рассмотрим основные правила XAML. Документ XAML записан в формате XML. Это означает, что имена элементов XAML чувствительны к регистру, нужна правильная вложенность элементов, некоторые символы требуют особого обозначения (например, & – это символ &).

Объектные элементы XAML описывают объект некоторого типа .NET (класса или структуры). Имя объектного элемента совпадает с именем типа. Необходимо, чтобы тип обладал открытым конструктором без параметров. Например, следующий объектный элемент описывает объект Button (кнопку):

<Button>Click me!</Button>

Типы .NET обычно вложены в пространства имён. В XAML пространство имён .NET ставится в соответствие пространству имён XML. Для этого используется следующий синтаксис:

xmlns:префикс="clr-namespace:ПространствоИмён"

При необходимости указывается сборка, содержащая пространство имён:

xmlns:префикс="clr-namespace:ПространствоИмён;assembly=ИмяСборки"

WPF XAML обычно использует два стандартных пространства имён:

  • http://schemas.microsoft.com/winfx/2006/xaml/presentation – соответствует набору пространств имён .NET с классами WPF;

  • http://schemas.microsoft.com/winfx/2006/xaml – содержит классы, используемые анализатором XAML (XAML parser).

Любые пространства имён, как правило, описываются в корневом элементе XAML. При этом первое из стандартных пространств имён обычно указывается без префикса, а значит, применяется по умолчанию ко всем элементам. Пространство имён анализатора XAML традиционно указывается с префиксом x.

<Window xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:sys="clr-namespace:System;assembly=mscorlib">

<Button>Click me!</Button>

</Window>

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

<Button Width="100" Foreground="Red">Click me!</Button>

Анализатор XAML применяет для преобразования строки в значение свойства специальные конвертеры типов. Набор стандартных конвертеров достаточно богат. При необходимости можно разработать собственный конвертер, используя базовый класс TypeConverter.

Элемент свойства – это дочерний элемент объектного элемента, имеющий вид <TypeName.Property>. Содержимое элемента свойства рассматривается как значение свойства:

<Button>

<Button.Width>100</Button.Width>

<Button.Foreground>Red</Button.Foreground>

Click me!

</Button>

Тип, соответствующий объектному элементу, может быть помечен атрибутом [ContentProperty] с указанием имени свойства содержимого. В этом случае анализатор XAML рассматривает содержимое объектного элемента как значение свойства содержимого. Например, в классе Button свойством содержимого является Content1:

[System.Windows.Markup.ContentProperty("Content")]

public class Button { . . . }

Это означает, что следующие два фрагмента XAML эквиваленты:

<Button Content="Click me!"/>

<Button>Click me!</Button>

Если тип реализует интерфейсы IList или IDictionary, при описании объекта этого типа в XAML дочерние элементы автоматически добавляются в соответствующую коллекцию. Например, свойство Items класса ListBox имеет тип ItemCollection, который реализует IList:

<ListBox>

<ListBox.Items>

<ListBoxItem Content="Item 1"/>

<ListBoxItem Content="Item 2"/>

</ListBox.Items>

</ListBox>

Кроме этого, Items – это свойство содержимого для ListBox, а значит, XAML-описание можно упростить:

<ListBox>

<ListBoxItem Content="Item 1"/>

<ListBoxItem Content="Item 2"/>

</ListBox>

Во всех предыдущих примерах использовалось конкретное указание значения свойства. Механизм расширений разметки (markup extensions) позволяет вычислять значение свойства при выполнении приложения. Встретив в XAML расширение разметки, анализатор генерирует код, который создаёт объект расширения разметки и вызывает особый метод объекта для получения значения.

Технически, любое расширение разметки – это класс, унаследованный от класса MarkupExtension и перекрывающий функцию ProvideValue():

using System;

using System.Windows.Markup;

namespace MarkupExtensions

{

public class ShowTimeExtension : MarkupExtension

{

public ShowTimeExtension() { }

public ShowTimeExtension(string header)

{

Header = header;

}

public string Header { get; set; }

public override object ProvideValue(IServiceProvider provider)

{

return string.Format("{0}: {1}", Header, DateTime.Now);

}

}

}

Если расширение разметки используется в XAML как значение атрибута, то оно записывается в фигурных скобках. Если имя расширения имеет суффикс Extension, этот суффикс можно не указывать. В фигурных скобках также перечисляются параметры конструктора расширения и пары для настройки свойств расширения в виде Свойство=Значение.

<Window xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:local="clr-namespace:MarkupExtensions">

<StackPanel>

<Button Content="{local:ShowTime First}"/>

<Button Content="{local:ShowTime Header=Second}"/>

</StackPanel>

</Window>

Расширения разметки могут применяться и в виде вложенных элементов:

<Button>

<Button.Content>

<local:ShowTime Header="First" />

</Button.Content>

</Button>

В табл. 1 представлены стандартные расширения разметки, доступные после подключения пространства имён анализатора XAML.

Таблица 1

Стандартные расширения разметки

Имя

Описание

x:Array

Представляет массив. Дочерние элементы становятся элементами массива:

<x:Array Type="{x:Type Button}">

<Button />

<Button />

</x:Array>

x:Null

Значение null

Background="{x:Null}"

x:Static

Представляет статическое свойство, поле или константу:

Height="{x:Static SystemParameters.IconHeight}"

x:Type

Аналог применения оператора typeof из языка C#

Анализатор XAML генерирует код, выполняющий по документу XAML создание и настройку объектов. Действия с объектами описываются в отдельном классе кода. Чтобы сослаться на объект в коде, объект должен иметь имя. Для этого в пространстве имён анализатора XAML определён атрибут Name:

<Button x:Name="okButton" Content="Click me!" />

Заметим, что многие элементы управления WPF имеют свойство Name. Анализатор XAML использует соглашение, по которому задание свойства Name эквивалентно указанию XAML-атрибута x:Name.

Чтобы связать класс кода с документом XAML используется атрибут Class из пространства имён анализатора XAML. Этот атрибут применяется только к корневому элементу и содержит имя класса, являющегося наследником класса корневого элемента:

<Window x:Class="WpfApplication1.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Button x:Name="okButton" Content="Click me!" />

</Window>

В заключение заметим, что WPF XAML описывает логическое дерево элементов. Наряду с этим термином используется понятие визуального дерева элементов. Визуальное дерево составляют отображаемые объекты. Некоторые одиночные логические объекты распадаются на несколько визуальных составляющих, так как строятся из нескольких визуальных примитивов. Например, любое окно Window включает визуальный примитив Border, который содержит примитив AdornerDecorator c объектами ContentPresenter и AdornerLayer.