Простейшее приложение WPF

Построим простейшее однооконное приложение WPF. Для этого создадим файл Program.cs и поместим в него следующий код:

using System;

using System.Windows;

public class Program

{

[STAThread]

public static void Main()

{

var myWindow = new Window();

myWindow.Title = "WPF Program";

myWindow.Content = "Hello, world";

var myApp = new Application();

myApp.Run(myWindow);

}

}

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

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

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

public class MainWindow : Window

{

public MainWindow()

{

Title = "WPF Program";

Content = "Hello, world";

}

}

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

– файл MainWindow.xaml.cs на языке C# и MainWindow.xaml на языке XAML описывают класс MainWindow, являющийся наследником класса Window;

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

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

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

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

Title="WPF Program" Height="250" Width="400">

Hello, world

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

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

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

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

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

XAML

Расширяемый язык разметки приложений (eXtensible Application Markup Language, XAML[1]) – это язык для представления дерева объектов .NET, основанный на XML. Данные XAML превращаются в дерево объектов при помощи анализатора XAML (XAML parser). Основное назначение XAML – описание пользовательских интерфейсов в приложениях WPF. Однако XAML используется и в других технологиях, в частности, в Silverlight.

Рассмотрим основные правила XAML. Документ XAML записан в формате XML. Это означает, что имена элементов XAML чувствительны к регистру, нужна правильная вложенность элементов, а некоторые символы требуют особого обозначения (например, & – это символ &). Кроме этого, XAML по умолчанию игнорирует лишние пробельные символы (однако это поведение изменяется установкой у элемента атрибута xml:space="preserve").



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

I am a Button

// определение объекта в коде

Button b = new Button();

b.Width = 100;

b.Content = "I am a Button";

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

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

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

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

Для нужд WPF зарезервировано два пространства имён XML:

1. http://schemas.microsoft.com/winfx/2006/xaml/presentation – обычно является пространством имён по умолчанию (указывается без префикса) и соответствует набору пространств имён .NET с типами WPF (эти пространства имён имеют вид System.Windows.*).

2. http://schemas.microsoft.com/winfx/2006/xaml – отвечает пространству имён System.Windows.Markup, а также позволяет выделить директивы (указания) для анализатора XAML. Пространству имён анализатора XAML по традиции ставят в соответствие префикс x.

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

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

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

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

Анализатор XAML применяет для преобразования строки в значение свойства специальные конвертеры типов (конвертеры не используются для строк, чисел и элементов перечислений). Приведённый выше фрагмент XAML эквивалентен следующему коду на C#:

// TypeConverter и TypeDescriptor определены в System.ComponentModel

var b = new Button();

TypeConverter convert = TypeDescriptor.GetConverter(typeof (Brush));

b.Background = (Brush) convert.ConvertFromInvariantString("Red");

Платформа .NET содержит более ста стандартных конвертеров. При необходимости можно разработать собственный конвертер, используя базовый класс TypeConverter.

Элемент свойства вложен в объектный элемент и имеет вид . Содержимое элемента свойства рассматривается как значение свойства (при необходимости применяются конвертеры). Обычно элементы свойств используются для значений, являющихся объектами.

100

Red

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

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

public class ContentControl

{

public object Content { get; set; }

// другие элементы класса ContentControl не показаны

}

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

Click me!

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

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

Во всех предыдущих примерах использовалось конкретное указание значения свойства. Механизм расширений разметки (markup extensions) позволяет вычислять значение свойства при преобразовании XAML в дерево объектов. Технически, любое расширение разметки – это класс, унаследованный от System.Windows.Markup.MarkupExtension и перекрывающий функцию ProvideValue(). Встретив расширение разметки, анализатор XAML генерирует код, который создаёт объект расширения разметки и вызывает ProvideValue() для получения значения. Приведём пример расширения разметки:

using System;

using System.Windows.Markup;

namespace MarkupExtensions

{

public class ShowTimeExtension : MarkupExtension

{

public string Header { get; set; }

public ShowTimeExtension() { }

public override object ProvideValue(IServiceProvider sp)

{

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

}

}

}

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

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

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

Расширения разметки могут применяться как значения элементов свойств:

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

Таблица 1

Расширения разметки из System.Windows.Markup

Имя Описание, пример использования
x:Array Представляет массив. Дочерние элементы становятся элементами массива
x:Null Представляет значение null Style="{x:Null}"
x:Reference Используется для ссылки на ранее объявленный элемент
x:Static Представляет статическое свойство, поле или константу Height="{x:Static SystemParameters.IconHeight}"
x:Type Аналог применения оператора typeof из языка C#

Рассмотрим некоторые директивы анализатора XAML, применяемые в WPF. Анализатор генерирует код, выполняющий по документу XAML создание и настройку объектов. Действия с объектами (в частности, обработчики событий) обычно описываются в отдельном классе. Чтобы связать этот класс с документом XAML используется директива-атрибут x:Class. Этот атрибут применяется только к корневому элементу и содержит имя класса, являющегося наследником класса корневого элемента:

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

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

Чтобы сослаться на объект в коде, этот объект должен иметь имя. Для указания имени объекта используется директива-атрибут x:Name:

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

Существует возможность встроить фрагмент кода в XAML-файл. Для этого используется директива-элемент x:Code. Такой элемент должен быть непосредственно вложен в корневой элемент, у которого имеется атрибут x:Class.

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

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

void btn_click(object sender, RoutedEventArgs e)

{

btn.Content = "Inline Code Works!";

}

]]>

Директива-атрибут x:Key применятся при описании дочерних элементов объекта-словаря, и позволяет указать ключ словаря для элемента:

В .NET Framework 4.0 была представлена новая версия XAML, известная как XAML 2009. XAML 2009 пока не используется при описании интерфейсов WPF-приложений, поэтому только упомянём его основные особенности:

– полная поддержка универсальных типов (generics);

– работа с базовыми типами .NET (числа, строки) без подключения дополнительных пространств имён;

– создание объектов, используя вызов конструктора с параметрами;

– создание объектов путём вызова заданного фабричного метода;

– расширенное управление обработчиками событий.

Платформа .NET включает классы, образующие программный интерфейс для работы с XAML. Большинство классов принадлежит пространству имён System.Xaml и находится в одноимённой сборке. Статический класс XamlServices содержит методы для сериализации объектов в формате XAML. Классы XamlReader, XamlWriter и их наследники дают доступ к структуре XAML-данных. Класс System.Windows.Markup.XamlReader осуществляет загрузку XAML и порождает соответствующее дерево объектов.

public class Book

{

public string Name { get; set; }

public int ISBN { get; set; }

}

// сериализация объекта класса Book в XAML-формате

var book = new Book {Name = "First", ISBN = 123};

XamlServices.Save("book.xaml", book);

// создание WPF-окна на основе XAML-описания

Window window = null;

using (Stream s = File.OpenRead("MyWindow.xaml"))

{

// предполагается, что тип корневого элемента известен

window = (Window) System.Windows.Markup.XamlReader.Load(s);

}

  • Строя отношения с человеком, ясно представляйте себе свою цель.
  • Выросшая в зажиточной семье Маргарет вела комфортную жизнь привилегированного класса. Но когда ее отец перевез семью на север, ей пришлось приспосабливаться к жизни в Милтоне — городе, переживающем 31 страница
  • When We Have Pain
  • МЕТОДИЧНІ ВКАЗІВКИ ДО ВИВЧЕННЯ ПИТАНЬ ТЕМИ
  • Обольщение Зевса
  • И кто есть кто?
  • Вклад грузооборота видов транспорта в общий прирост грузооборота транспортной системы страны, 2010 г.
  • В.И. Покровский, С.Г. Пак, Н.И. Брико, Б.К. Данилкин 71 страница
  • Статья 1. Предмет регулирования настоящего Федерального закона
  • Характеристика Ненецкого автономного округа.
  • Море и пляжи
  • Глава III. Культурно-историческая детерминация переживания.
  • Инсулин - максимальная выработка Править
  • ПРОСТО ПРОЧТИТЕ ДО КОНЦА. Сразу, все это не удаляйте - на самом деле классная вещь, почитайте - сейчас или на досуге, переспите с новыми мыслями на этот счет и там как знаешь. Если у Вас есть
  • О ГРАЖДАНСТВЕННОСТИ ИСКУССТВА 6 страница
  • Динамика экспорта страны (по выбору) за 2000-2007 годы.
  • Ребенок бьет окружающих
  • MZP[1] яяё@є ­ґ Н!ёLН!ђђThis program must be run under Win32 85 страница
  • Глава 1. Есть ли у меня потенциал?
  • Способы бисероплетения