“
Переходим к следующей теме, и сегодня мы узнаем, как создать каркас приложения с помощью технологии WPF, а заодно познакомимся с ее основными механизмами.
Для успешного освоения материала рекомендуем вам изучить следующие понятия:
Windows Presentation Foundation. Аналог WinForms, система для построения клиентских приложений Windows с визуально привлекательными возможностями взаимодействия с пользователем, графическая (презентационная) подсистема в составе .NET Framework (начиная с версии 3.0), использующая язык XAML
Desktop application. Программное обеспечение, предназначенное для работы на персональных компьютерах
Control. Элемент, который предназначен для взаимодействия с пользователем или для отображения ему какой-либо информации
Использование Windows Presentation Foundation (WPF) для создания интерактивных настольных приложений
Cоздание нового проекта
1. Запустить среду разработки Visual Studio
2. Выбрать «Create new project»
4. Заполнить графу «Project name»
При разработке интерфейсов разработчик может использовать две модели: оконную или страничную (в настоящее время используют чаще)
Оконная модель:
Элементы управления в приложении
Интерфейс состоит из элементов управления, которые непосредственно взаимодействуют с пользователем или отображают какую-либо информацию
Доступные элементы управления находятся на панели Toolbox
Использование Windows Presentation Foundation (WPF) для создания интерактивных настольных приложений
Контейнеры компановки
1. Grid
Наиболее мощный и часто используемый контейнер, похожий на таблицу. Он содержит столбцы и строки, количество которых можно задать. Для определения строк используется свойство RowDefinition,
а для столбцов — ColumnDefinition
Важно
Для привязки элемента управления к конкретной ячейке необходимо использовать свойства Grid.Column и Grid.Row, причем нумерация строк и столбцов начинается с нуля
2. StackPanel
Позволяет размещать элементы управления поочередно друг за другом
Также существует возможность выбора ориентации размещения с помощью свойства Orientation
Перед стилизацией разметим окно приложения с помощью контейнера Grid
Добавим логотип приложения в Resourses
1. Выбрать вкладку ToursApp
2. Открыть вкладку Resources
3. Выбрать список изображений
4. Перетащить логотип в открывшееся окно
5. Установить значение поля Build Action — Resource
Для отображения логотипа используем элемент Image
Установим заголовок приложения
Установим цвета для верхней и нижней частей
Для оконной навигации основным элементом является страница — Page, которая должна находиться в каком-либо контейнере. Для этого в основном окне приложения разместим элемент Frame, где будут собраны страницы приложения
Далее создадим страницу, которая будет отображаться при первом запуске приложения, и вторую страницу для тестирования навигации между ними
1. Правой кнопкой жмем на название проекта — Add — Page
2. Указываем ее название, например, HotelsPage
3. Размещаем на странице одну кнопку
4. Создаем еще одну страницу, повторив пункт 1
5. Даем ей название AddEditPage
6. Размещаем в ней TextBlock
Для того, чтобы использовать созданные элементы в приложении, необходимо указывать для них имена. Имя — это тоже одно из свойств, по которому можно обращаться к тем или иным элементам в коде. Укажем имя фрейма:
Для отображения первой страницы необходимо прописать следующий код (для перехода в нужное окно нажмите F7): ‘MainFrame.Navigate(new HotelPage());’
Свойства элементов управления
Например:
- Background — меняет фоновый цвет элемента
Все свойства элемента можно посмотреть в окне Properties. Там же можно найти все возможные события, доступные для выбранного элемента управления.
Для взаимодействия с кнопкой будем использовать событие Click(). С помощью него мы сможем перейти с первой страницы на вторую. Для создания события пропишем соответствующее значение в верстке:
Далее нажмем F12 и попадем в окно обработки нажатия на кнопку. Чтобы добраться до MainFrame для навигации, необходимо создать новый класс:
1. Правой кнопкой на название проекта — Add — Class
2. Вводим название класса
3. Создаем статичное свойство MainFrame
4. Присваиваем ему значение в MainWindow
Теперь можем создать навигацию на главной странице
Добавим кнопку «Назад» на главном окне приложения. Установим для нее следующие свойства:
- Name
- Width, Height
- HorizontalAlignment, Margin
Далее нажимаем F12 и попадаем в окно обработки нажатия на кнопку. Используем следующую логику: обращаемся к менеджеру (Manager), к фрейму (MainFrame) и вызываем метод GoBack
Но она не нужна на главном экране. Чтобы скрыть ее, воспользуемся событием ContentRendered
А чтобы скрыть стандартное навигационное меню, воспользуемся свойством фрейма — NavigationUIVisibility=’Hidden’
Глобальные стили приложения
Для большинства созданных элементов мы использовали похожий набор свойств: ширина, высота, размер шрифта, отступы и др. Чтобы применять определенные наборы свойств для элементов, WPF предлагает использование глобальных стилей в проекте. Чтобы их создавать в проекте, есть файл App.xaml. Используем тег Style и свойство TargetType, чтобы указать, для каких элементов предназначен данный стиль.
Внутри тега Style используем тег Setter. В нем установим необходимые свойства:
И теперь удалим написанные ранее свойства элементов, для которых есть стиль
“
Мы получили краткое руководство по первым шагам создания приложения на платформе WPF. При компоновке макета приложения приходится писать некоторое количество кода, но механизмы, заложенные в данную платформу, значительно сокращают время на разработку дизайна и логики приложения в целом.
А теперь проверьте полученные знания на практике.
Для закрепления полученных знаний пройдите тест
WPF. Что представляет собой TextBox?
Элемент управления, предназначенный для ввода текста
Набор текстовых командных блоков
Текстовая метка без возможности редактирования текста
WPF. Какое свойство используется для определения строк в Grid?
К сожалению, вы ответили неправильно
Прочитайте лекцию и посмотрите видео еще раз
Но можно лучше. Прочитайте лекцию и посмотрите видео еще раз
Вы отлично справились. Теперь можете ознакомиться с другими компетенциями
Всем привет!
По разным причинам большинство из нас использует десктопные приложения, как минимум, браузер А у некоторых из нас возникает необходимость в написании своих. В этой статье я хочу пробежаться по процессу разработки несложного десктопного приложения с использованием технологии Windows Presentation Foundation (WPF) и применением паттерна MVVM. Желающих продолжить чтение прошу под кат.
Думаю, необязательно говорить, что WPF — это разработка Microsoft Технология эта предназначена для разработки десктопных приложений под Windows, начиная с Windows XP. Почему именно так? Это связано с тем, что WPF работает поверх платформы .NET, минимальные требования которой — Windows XP и новее. К сожалению, WPF не работает на других платформах, хотя есть шансы, что в ближайшее время это изменится: в стадии разработки находится WPF-based фреймворк Avalonia.
В чём особенность WPF?
Два основных отличия WPF от других средств построения десктопных приложений:
- Язык разметки XAML, предназначенный для разметки самого интерфейса окна.
- Рендеринг посредством DirectX, аппаратное ускорение графики.
Я не буду углубляться в подробности, т.к. это не совсем тема статьи. Если интересно, то гуглить XAML, WPF rendering, milcore.dll и DirectX
О чём эта статья?
Эта статья содержит пример приложения, построенного на технологии WPF:
- MVVM и интерфейс INotifyPropertyChanged. Копия текста.
Я постараюсь ориентировать материал статьи в практическую сторону в стиле «повторяй за мной» с пояснениями.
Что нам понадобится для повторения статьи?
Небольшой опыт разработки на C# Как минимум, нужно хорошо понимать синтаксис языка. Также понадобится Windows-машина (в примерах будет Win 10) с установленной на ней Visual Studio (в примерах будет 2017, есть бесплатная Community версия). При установке VS необходимо будет включить поддержку десктопной разработки под платформу .NET
Так же в этом разделе я опишу создание проекта.
Запускаем VS, создаём новый проект, тип приложения выбираем WPF App (.NET Framework) (можно ввести в строке поиска справа вверху), называем как угодно.
После создания нового проекта откроется окно редактора интерфейса, у меня оно выглядит так
Внизу находится редактор разметки, вверху — предпросмотр интерфейса окна, но можно поменять относительное расположение редактора кода и предпросмотра интерфейса так, что они будут располагаться в горизонтальном порядке, с помощью вот этих кнопок (справа на границе двух областей):
Перед тем, как начать
Элементы окна (их ещё называют контрОлами от слова Control) должны размещаться внутри контейнера или внутри другого элемента типа ContentControl. Контейнер — это специальный контрол, позволяющий разместить внутри себя несколько дочерних контролов и организовать их взаимное расположение. Примеры контейнеров:
- Grid — позволяет организовать элементы по столбцам и строкам, ширина каждого столбца или строки настраивается индивидуально.
- StackPanel — позволяет расположить дочерние элементы в одну строку или столбец.
Есть и другие контейнеры. Поскольку контейнер тоже является контролом, то внутри контейнера могут быть вложенные контейнеры, содержащие вложенные контейнеры и так далее. Это позволяет гибко располагать контролы относительно друг друга. Так же с помощью контейнеров мы можем не менее гибко управлять поведением вложенных контролов при изменении размеров окна.
MVVM и интерфейс INotifyPropertyChanged. Копия текста.
Итогом этого примера станет приложение с двумя контролами, в одном из которых можно редактировать текст, а в другом только просматривать. Изменения из одного в другой будут переходить синхронно без явного копирования текста с помощью привязки (binding).
Итак, у нас есть свежесозданный проект (я назвал его Ex1), перейдём в редактор разметки и первым делом заменим контейнер, указанный по умолчанию (<Grid></Grid>) на <StackPanel></StackPanel>. Этого контейнера будет достаточно, т.к. нам понадобится расположить всего лишь два контрола один над другим. Укажем явно, каким образом будут располагаться компоненты, добавив свойство Orientation=»Vertical». Добавим внутрь стек панели парочку элементов: поле для ввода текста и поле для отображения текста. Поскольку эти контролы не будут содержать вложенного кода, можно описать их самозакрывающимся тегом (см. код ниже). После всех вышеописанных процедур код описания контейнера и вложенных контролов должен принять такой вид:
<StackPanel Orientation="Vertical">
<TextBox />
<TextBlock />
</StackPanel>
Теперь сосредоточимся на цели этого примера. Мы хотим, чтобы при наборе текста в текстбоксе этот же текст синхронно отображался в текстблоке, избежав при этом явной операции копирования текста. Нам понадобится некая связующая сущность, и вот тут-то мы и подошли к такой штуке, как привязка (binding), о которой было сказано выше. Привязка в терминологии WPF — это механизм, позволяющий связывать некоторые свойства контролов с некоторыми свойствами объекта C#-класса и выполнять взаимное обновление этих свойств при изменении одной из частей связки (это может работать в одну, в другую или в обе стороны сразу). Для тех, кто знаком с Qt, можно провести аналогию слотов и сигналов. Чтобы не растягивать время, перейдём к коду.
Итак, для организации привязки нужны свойства контролов и некое свойство некоего C#-класса. Для начала разберёмся с XAML-кодом. Текст обоих контролов хранится в свойстве Text, поэтому добавим привязку для этих свойств. Делается это так:
<TextBox Text="{Binding}"/>
<TextBlock Text="{Binding}"/>
Мы сделали привязку, но пока непонятно к чему Нам нужен объект какого-то класса и какое-то свойство в этом объекте, к которому будет выполнена привязка (как ещё говорят, на которое нужно забиндиться).
Так что это за класс? Этот класс называется вьюмоделью (view model) и служит как раз связующим звеном между view (интерфейсом или его частями) и model (моделью, т.е. теми частями кода, которые отвечают за логику приложения. Это позволяет отделить (в какой-то степени) логику приложения от интерфейса (представления, view) и называется паттерном Model-View-ViewModel (MVVM). В рамках WPF этот класс также называется DataContext.
Однако, просто написать класс вьюмодели недостаточно. Нужно ещё как-то оповещать механизм привязки о том, что свойство вьюмодели или свойство вью изменилось. Для этого существует специальный интерфейс INotifyPropertyChanged, который содержит событие PropertyChanged. Реализуем этот интерфейс в рамках базового класса BaseViewModel. В дальнейшем все наши вьюмодели мы будем наследовать от этого базового класса, чтобы не дублировать реализацию интерфейса. Итак, добавим в проект каталог ViewModels, а в этот каталог добавим файл BaseViewModel.cs. Получим такую структуру проекта:
Код реализации базовой вьюмодели:
using System.ComponentModel;
namespace Ex1.ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Создадим для нашего класса MainWindow свою вьюмодель, унаследовавшись от базовой. Для этого в том же каталоге ViewModels создадим файл MainWindowViewModel.cs, внутри которого будет такой код:
namespace Ex1.ViewModels
{
public class MainWindowViewModel : BaseViewModel
{
}
}
Шикарно! Теперь нужно добавить в эту вьюмодель свойство, на которое будем биндить текст наших контролов. Поскольку это текст, тип этого свойства должен быть string:
public string SynchronizedText { get; set; }
В итоге получим такой код
namespace Ex1.ViewModels
{
public class MainWindowViewModel : BaseViewModel
{
public string SynchronizedText { get; set; }
}
}
Так, кажется, справились. Осталось забиндиться на это свойство из вьюхи и готово. Давайте сделаем это прямо сейчас:
<TextBox Text="{Binding Path=SynchronizedText}"/>
<TextBlock Text="{Binding Path=SynchronizedText}"/>
Ништяк, запускаем проект, набираем текст в текстбокс иииии… ничего не происходит))) Ну, ничего страшного, на самом деле мы идём правильной дорогой, просто пока ещё не дошли до нужной точки.
Предлагаю на минутку остановиться и подумать, чего же нам не хватает. Вьюха у нас есть. Вьюмодель тоже. Свойства вроде забиндили. Нужный интерфейс реализовали. Проделали кучу работы ради копирования жалкой строчки текста, за что нам это???!?!111
Ладно, шутки в сторону. Мы забыли создать объект вьюмодели и кое-что ещё (об этом позже). Сам класс мы описали, но это ничего не значит, ведь у нас нет объектов этого класса. Ок, где нужно хранить ссылку на этот объект? Ближе к началу примера я упомянул некий DataContext, используемый в WPF. Так вот, у любой вью есть свойство DataContext, которому мы можем присвоить ссылку на нашу вьюмодель. Сделаем это. Для этого откроем файл MainWindow.xaml и нажмём F7, чтобы открыть код этой вьюхи. Он практически пустой, в нём есть только конструктор класса окна. Добавим в него создание нашей вьюмодели и поместим её в DataContext окна (не забываем добавить using с нужным неймспейсом):
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
Это было просто, но этого всё равно не хватает. По-прежнему при запуске приложения никакой синхронизации текста не происходит. Что ещё нужно сделать?
Нужно вызвать событие PropertyChanged при изменении свойства SynchronizedText и сообщить вьюхе о том, что она должна следить за этим событием. Итак, чтобы вызвать событие, модифицируем код вьюмодели:
public class MainWindowViewModel : BaseViewModel
{
private string _synchronizedText;
public string SynchronizedText
{
get => _synchronizedText;
set
{
_synchronizedText = value;
OnPropertyChanged(nameof(SynchronizedText));
}
}
}
Что мы тут сделали? Добавили скрытое поле для хранения текста, обернули его в уже существующее свойство, а при изменении этого свойства не только меняем скрытое поле, но и вызываем метод OnPropertyChanged, определённый в базовой вьюмодели и вызывающий событие PropertyChanged, объявленное в интерфейсе INotifyPropertyChanged, так же реализованное в базовой вьюмодели. Получается, что при каждом изменении текста возникает событие PropertyChanged, которому передаётся имя свойства вьюмодели, которое было изменено.
Ну, почти всё, финишная прямая! Осталось указать вьюхе, что оно должно слушать событие PropertyChanged:
<TextBox Text="{Binding Path=SynchronizedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWayToSource}"/>
<TextBlock Text="{Binding Path=SynchronizedText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"/>
Помимо того, что мы указали, по какому триггеру должно происходить обновление, мы так же указали, в какую сторону это обновление отслеживается: от вью к вьюмодели или наоборот. Поскольку в текстбоксе мы вводим текст, то нам интересны изменения только во вью, поэтому выбираем режим OneWayToSource. В случае с текстблоком всё ровно наоборот: нам интересны изменения во вьюмодели, чтобы отобразить их во вью, поэтому выбираем режим OneWay. Если бы нам нужно было, чтобы изменения отслеживались в обе стороны, можно было не указывать Mode вообще, либо указать TwoWay явно.
Итак, запускаем программу, набираем текст и voi-la! Текст синхронно меняется, и мы нигде ничего не копировали!
Спасибо за внимание, продолжение следует. Будем разбираться с DataTemplate и паттерном Command.
Аннотация: Начинается описание технологии программирования Windows Presentation Fondation. На примере упражнений подробно показан процесс создания и работы приложений и окон WPF, а также представлен язык разметки XAML.
Совершенно новой технологией программирования, которая стала
поддерживаться Microsoft, начиная с библиотеки .NET Framework 3.0, является WPF —
Windows Presentation Fondation (ранее носившая кодовое
название Avalon). Эта библиотека еще не так
развита в плане разнообразия библиотечных компонентов, как Windows Forms, но
открывает для будущего широкие перспективы и является одной из частей нового
API будущих версий Windows.
Существует два вида программ: для взаимодействия с людьми и для
взаимодействия с другими программами. Технология WPF ориентирована как раз
для взаимодействия с людьми. Многие подходы к созданию
приложений в WPF ориентированы на упрощение процесса программирования пользовательских
интерфейсов, что может значительно расширить круг программистов разного уровня
подготовки, способных создавать приложения промышленного уровня.
Не смотря на то, что .NET создавалась независимой от платформы
и должна бы работать на любой системе, WPF скорей всего, не сможет жить в любой
среде — уж слишком сильно прослеживается связь с Windows
и DirectX. Уже сейчас есть ограничения на используемую версию ОС Windows:
минимальным требованием является Windows XP SP2.
В Windows XP и Windows 2003 требуется отдельная установка, в то время как в
Windows Vista данная подсистема уже предоставлена.
Новая графическая система Windows Presentation Foundation предназначена
для создания пользовательских интерфейсов, 2D и 3D графики и т. д. Мощь WPF
заключается в том, что 2D графика строится в векторном виде, а это значит,
что интерфейсы будут максимально независимы от разрешения экрана и размера
окна. Они будут легко масштабироваться без потери качества и быстро работать
благодаря максимальному использованию возможностей современных графических
ускорителей.
WPF включает в себя язык разметки XAML —
Extensible Application Markup Language (произносится «заммль» — расширяемый
язык разметки приложений )
как подмножество (диалект) языка XML и используется для создания и инициализации
объектов. Использование языка XAML позволяет участвовать в разработке приложений
людям с различными знаниями и опытом программирования. XAML — это мост между
программистами и дизайнерами.
XAML использует основные четыре категории элементов:
- панели размещения
- элементы
управления - элементы, связанные с документом
- графические фигуры
WPF объединяет
документы, формы и мультимедийное содержание в пакет, состоящий из языка
разметки и процедурного языка программирования. Такой подход все больше стирает
грань между Windows— и Web-программированием, сохраняя их лучшие достижения
и традиции. Модель программирования WPF включает в себя одновременно декларативную (разметка)
и императивную (кодовую, процедурную, бизнес-логику) части.
Теперь внешний вид приложения может создавать дизайнер,
а не программист. Он может
создавать окна в специализированных и простых программах, а программист в это
время может писать логику. Таким образом, работа идет параллельно, а результирующий
продукт может появиться на рынке быстрее. Когда дизайном занимается профессионал,
то интерфейс будет смотреться намного лучше, чем работа программиста. Программисты
должны писать код, а не рисовать.
Для дизайнеров Microsoft предлагает продукт под названием Microsoft Expression
Blend (http://www.microsoft.com/expression). Это программа специально написана
для специалистов интерфейса, а не программистов и не требует знания языков
программирования.
WPF построен поверх DirectX, что позволяет
использовать всю мощь современного «железа». Так, например, когда WPF определяет
наличие видеокарты, поддерживающей аппаратное ускорение, он автоматически
использует эти возможности карты. Использование WPF требует серьезной
аппаратной поддержки — наличия графического процессора, поддерживающего DirectX 9.
Рендеринг в WPF – векторный, это дает возможность использовать
преимущества мониторов с высоким разрешением, без каких либо дополнительных
усилий программиста или пользователя. Интерфейс пользователя больше не зависит
от конкретных разрешений, введено понятие «виртуального пиксела».
WPF Framework позволяет программистам создавать продвинутые приложения с
богатым пользовательским интерфейсом, работающие с мультимедиа, изощренно работать
с документами: все это объединено в единой программной модели. WPF предлагает
множество различных элементов управления для:
- стандартных форм (такие как кнопки и элементы ввода)
- документов
- изображений и видео
- графических примитивов
- 3D
- различных контейнеров и панелей для размещения элементов управления
XAML содержит ровно одну корневую вершину и является деревом отображения.
На вершине иерархии находится один из контейнерных объектов. Внутри этих объектов
располагаются элементы управления и другие контейнеры. В XAML названия
элементов всегда чувствительны к регистру и точно совпадают с именами классов,
доступных в кодовой части WPF.
Упражнение 1. Пример создания простой кнопки с элементом анимации
В этом упражнении мы просто продемонстрируем на простом примере
некоторые мультимедийные возможности WPF.
Создание заготовки приложения
-
Создайте проект WpfApp1 в решении WpfApp как показано на рисунке. Обратите внимание на необходимость
выбора библиотеки .NET Framework 3.0.
Оболочка создаст заготовку с рабочей областью, представленной
на рисунке
Оболочка предоставляет возможность графического и дескрипторного
способов разработки пользовательского интерфейса, которые являются равнозначными.
Она сама подключила необходимые сборки и сгенерировала код поддержки WPF. На
данном этапе нас интересуют файлы: дескрипторный Window1.xaml и кодовый Window1.xaml.cs,
которые дополняют друг друга при описании одного и того же содержимого — класса Window1
(по умолчанию) в пространстве имен WpfApp1, совпадающем с названием проекта.
Платформа WPF проектировалась разработчиками с желанием отделить
дизайнерскую часть пользовательского интерфейса от кодовой части программирования
функциональности. Дизайнерская часть проектируется декларативно, чаще всего
— с помощью графического дизайнера формы, который в автоматическом режиме генерирует
соответствующий синтаксически правильный дескрипторный код на языке XAML.
Предполагается,
что разработчик, занимающийся дизайном формы, не должен вмешиваться в часть
XAML, а должен использовать только режим Design, чтобы не нарушить синтаксис
XAML. Но на практике опытный разработчик создает интерфейс окна именно в
дескрипторной части вручную, периодически проверяя представление через дизайнер
окна.
В заготовки дескрипторного XAML-кода видно, что корнем приложения
будет контейнер <Window>, в который при развитии проекта будут включены дочерние
элементы. Все элементы WPF существуют в двух вариантах: дескрипторном
и объектном. Объектное описание размещается в пространствах имен, подключаемых
в кодовую часть проекта с помощью инструкции using для видимости компилятором.
Дескрипторное описание находится в двух пространствах имен: обычном и расширенном.
Эти пространства имен подключаются как значения атрибутов xmlns и xmlns:x в
корневом дескрипторе проекта
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Это не ссылки на какие-то страницы Интернета, таких страниц не
существует, это разработчики платформы просто выбрали такие пространства
имен. Если убрать эти атрибуты из корневого элемента дескрипторной части XAML
проекта, то ни один дескриптор
не будет виден оболочкой.
1.
WINDOWS PRESENTATION
FOUNDATION 4
2. Базовые сведения
Windows Presentation Foundation (WPF) —
система
для
построения
клиентских
приложений Windows с визуально привлекательными
возможностями взаимодействия с пользователем,
графическая (презентационная)
подсистема
в
составе .NET Framework (начиная с версии 3.0),
использующая язык XAML.
3. Преимущества WPF
Технология WPF существенно упрощает создание
любых пользовательских интерфейсов. При этом
интерфейс может создаваться относительно независимо
от остального приложения, что позволяет дизайнерам
гораздо
эффективнее
участвовать
в
процессе
разработки приложения.
4. Особенности WPF
WPF предустановлена в Windows Vista, Windows 7,
Windows 8.
WPF предоставляет средства для создания
визуального
интерфейса,
включая
язык XAML (Extensible Application Markup
Language),
элементы
управления,
привязку
данных, макеты, двухмерную и трёхмерную
графику, анимацию, стили, шаблоны, документы,
текст, мультимедиа и оформление.
5. Особенности WPF
В основе WPF лежит векторная система
визуализации, не зависящая от разрешения
устройства вывода и созданная с учётом
возможностей
современного
графического
оборудования.
Графической технологией, лежащей в основе WPF,
является DirectX, в отличие от Windows Forms, где
используется GDI/GDI+.
производительность WPF выше, чем у GDI+ за
счёт использования аппаратного ускорения
графики через DirectX
6. Технология Silverlight и WPF
Технологию Silverlight является подмножеством WPF
и
дополнительно
включает
несколько
фундаментальных
классов
из
каркаса
.NET
Framework (встроенные типы данных, классы
коллекций и т. д.).
Если требуется функциональность, которая существует
только в полной версии .NET, то рекомендуется
использовать WPF. Если необходима возможность
выполнять приложение на компьютерах Мас или
устройствах, отличных от стандартного ПК, то
используется Silverlight.
На любой платформе Silverlight обеспечивает единую
технологию построения интерфейса.
7. Создание WPF-приложения
Создание WPF приложения начинается с
процедуры задания размеров и положений
элементов управления (и других элементов) –
компоновки или верстки макета.
В WPF имеется богатая инфраструктура
компоновки. В ее основе лежит механизм
взаимодействия между элементами-родителями
и их потомками.
8. Панели WPF
Родительские
элементы,
поддерживающие
компоновку нескольких детей, называются
панелями.
WPF пять основных встроенных панелей (все в
пространстве имен System.Windows.Controls) в
порядке возрастания сложности (и полезности):
Canvas;
StackPanel;
WrapPanel;
DockPanel;
Grid.
9.
Виды панелей
1)Canvas (холст) — самая простая панель. Использовать для
организации пользовательского интерфейса не рекомендуется.
2)StackPanel последовательно размещает своих потомков в виде
стопки.
3)Панель WrapPanel похожа на StackPanel, но при нехватке
места для одной стопки создает новые строки или столбцы.
4)Панель DockPanel дает простой способ пристыковки элемента
к одной из сторон, растягивая его на всю имеющуюся ширину
или высоту.
5)Grid(сетка) — самая гибкая из всех панелей и, пожалуй,
наиболее употребительная. В проектах VisualStudio и
ExpressionBlend панель Grid используется по умолчанию. Она
позволяет расположить дочерние элементы в несколько строк и
несколько столбцов, не полагаясь на режим автоматического
переноса.
10.
Свойства панелей
11. Свойства Height и Width
Во всех классах, производных от FrameworkElement,
есть свойства Height (высота) и Width (ширина) (типа
double), а также MinHeight, MaxHeight, MinWidth и
MaxWidth, которыми можно пользоваться для
задания допустимых диапазонов значений. Все эти
свойства можно задавать в любой комбинации как в
процедурном коде, так и в XAML.
12. Свойства Margin и Padding
Свойства Margin и Padding тоже связаны с размером
элемента.
Margin задает внешнее поле вокруг элемента, a
Padding — внутренний отступ между содержимым
элемента и его границами.
Результат установки разных свойств Margin и
Padding
13. Выравнивание
С
помощью
свойств
HorizontalAlignment
и
VerticalAlignment
элемент
может
управлять
распределением
избыточного
пространства,
выделенного ему родителем. Значениями свойств
являются
одноименные
перечисления,
которые
определены в пространстве имен System.Windows:
— HorizontalAlignment — Left, Center, Right, Stretch
— VerticalAlignment — Top, Center, Bottom, Stretch
Пример:
14. Применение преобразований
• В WPF имеется ряд встроенных классов
двумерных геометрических преобразований
(производных от
System.Windows.Media.Transform), которые
позволяют изменять размер и положение
элементов независимо от ранее
рассмотренных свойств.
• Встроенные двумерные преобразования, определенные в
пространстве имен System.Windows.Media:
• RotateTransform;
• ScaleTransform;
• SkewTransform;
15.
Примеры преобразований
RotateTransform
SkewTransform
ScaleTransform
16. Маршрутизируемые события и команды
Рассмотрим две важных составных части
инфраструктуры
WPF
маршрутизируемые
события и команды.
17.
Маршрутизируемые события
Сгенерированное
маршрутизируемое
событие
может
распространяться вверх или вниз по визуальному и
логическому дереву, достигая каждого элемента простым и
естественным образом без написания дополнительного кода.
Маршрутизация
событий
позволяет
большинству
приложений вообще не задумываться о наличии визуального
дерева и является основой механизма композиции элементов
в WPF.
События жестко связаны с деталями конкретных действий
пользователя (например, нажатие кнопки или выбор
элемента ListBoxItem из списка). Для различных устройств
ввода определены свои события. Существуют события:
клавиатуры;
мыши;
стилуса.
18.
Команды
В WPF существуют команды – это более абстрактная и слабо
связанная версия событий. Команды представляют действия
независимо от того, как они выглядят в пользовательском
интерфейсе. Каноническими примерами служат команды
Cut (Вырезать), Сору (Копировать) и Paste (Вставить). Мощь
механизма команд основывается на трех основных
особенностях:
в WPF определено много встроенных команд;
в команды встроена автоматическая поддержка жестов
ввода (например, сочетаний клавиш);
встроенное поведение некоторых элементов управления
WPF уже ориентировано на те или иные команды.
19. Элементы управления
Есть три основных разновидности однодетных
элементов управления:
— Кнопки
— Простые контейнеры
— Контейнеры с заголовками
20.
Примеры элементов управления
21. Двумерная графика
Основное отличие WPF от GDI — это то, что в WPF
работающая
применяется
графическая
система,
запоминания,
а
не
полностью
в
режиме
непосредственной визуализации.
В системе, работающей в режиме запоминания,
можно формулировать высокоуровневые указания,
например: «Помести синий квадрат размером 10×10
точку (0,0), — и система сама запомнит и будет
поддерживать это состояние. На самом деле это
означает: «Помести синий квадрат размером 10×10 в
точку (0,0) и следи за тем, чтобы он там оставался».
В дальнейшем нет необходимости возиться с
недействительными областями и перерисовкой, а это
экономит немало времени.
22. Двумерная графика
Существует три типа данных: Drawing, Visual и
Shape.
Drawing — это просто описания путей и фигур с
ассоциированными кистями Brush для заливки и
контура.
Визуальное представление Visual — это один из
способов нарисовать объект Drawing на экране, но класс
Visual открывает также возможность низкоуровневого и
менее
ресурсоемкого
подхода
к
рисованию,
позволяющего обходиться вообще без объектов Drawing.
Фигуры Shape — это готовые объекты Visual,
предлагающие
самый
простой
(но
и
самый
ресурсоемкий) подход к рисованию на экране.
23. Трёхмерная графика
Трехмерная графика (или ЗD-графика) полностью
интегрирована
в
платформу
WPF,
многие
встречающиеся в ней концепции пересекаются с
двумерной графикой и другими компонентами. Как
и в случае двумерной графики, возможности 3D
доступны как из процедурного кода, так и из XAMLразметки. Чтобы отобразить в WPF трехмерную
сцену, необходимо построить граф объектов. После
того как сцена описана, система берет на себя
ответственность за ее визуализацию и перерисовку в
нужные моменты времени.
24. Трёхмерная графика
Задача трехмерной графики — создание по
трехмерным моделям двумерных изображений,
которые можно было бы отобразить на некоем
устройстве вывода, например на экране монитора.
Хотя большинство ЗD-классов — прямые
обобщения двумерного API, есть два понятия, не
имеющих аналогов в двумерном мире:
Материалы Material и источники света Light
Камеры Camera
25.
Камера
В WPF для управления тем, что появится в объекте
Viewport3D, необходимо поместить на 3D-сцену
виртуальную камеру (объект Camera). Для этого
следует позиционировать и ориентировать камеру в
мировой системе координат (иногда для краткости ее
называют мировым пространством). На рисунке
показаны
двумерная
и
трехмерная
системы
координат, применяемые в WPF.
26.
Освещение
трех
основных
Освещение
складывается
из
компонентов:
объекты Light, являющиеся источниками света;
объекты Material, то есть материалы, по-разному
отражающие свет в камеру;
геометрия (Geometry) модели, определяющая углы
падения и отражения света.
Рассмотрим
различные
источники
освещения,
поддерживаемые WPF.
27.
Виды источников света
DirectionalLight (направленный источник
света) — расположен в бесконечности,
освещает сцену параллельными лучами
света.
Этот
класс аппроксимирует
удаленный источник света, например
Солнце.
PointLight
(точечный
источник)
—
излучает свет равномерно во всех
направлениях. Яркость света убывает с
увеличением расстояния от источника.
Класс
PointLight
аппроксимирует
нефокусированные
источники
света,
например электрические лампочки.
28.
Виды источников света
SpotLight (прожектор) — испускает конус
света. Яркость убывает с увеличением
расстояния от источника. Класс SpotLight
аппроксимирует фокусированные
источники света, например луч фонаря.
AmbientLight (рассеянный свет) —
освещает все поверхности равномерно.
Яркий источник рассеянного света создает
плоские изображения из-за отсутствия
теней. Однако не слишком яркий источник
аппроксимирует эффект рассеянного
освещения, созданного диффузно
отражающими поверхностями на сцене.
29.
Анимация, аудио и видео
Анимация
В WPF у анимации есть следующее определение: изменение
значения свойства во времени (цвета, размера, положения и т.п.).
Аудио
Средства работы с аудио представлены следующими классами:
SoundPlayer
SoundPlayerAction
MediaPlayer
MediaElement и MediaTimeline
Видео
Поддержка видео в WPF основана на классе MediaPlayer, а
также на сопутствующих ему классах MediaElement и
MediaTimeline.
Таким
образом,
все
форматы
файлов,
поддерживаемые Windows Media Player (WMV, AVI, MPG и
прочие), поддерживаются и WPF-приложениями.
Текст работы размещён без изображений и формул.
Полная версия работы доступна во вкладке «Файлы работы» в формате PDF
В настоящее время актуальна проблема визуализации информации, разработки графических интерфейсов. В статье описаны основы использования технологии Windows Presentation Foundation (WPF) для создания графического интерфейса десктопного приложения. Выделены понятие и особенности WPF, рассмотрены возможности данной технологии на примере разработки простого приложения «Список дел». Приведено краткое описание и структура разрабатываемого приложения, подробно разобрано представление его визуальной части на языке разметки XAML (файл MainWindow.xaml). На основе полученных практических результатов работы сделан вывод о значимом преимуществе использования технологии WPF в разработке, которое заключается в возможности разделения графического интерфейса приложения и его поведения от внутренней логики программы. Реализация данной возможности ведет к повышению эффективности архитектуры и быстродействия разрабатываемого приложения.
Ключевые слова: изучение сред программирования, визуальный интерфейс, десктопное приложение, WindowsPresentationFoundation, язык разметки XAML, преимущества WindowsPresentationFoundation.
Grebneva Daria Mikhailovna, Pakharukov Vitaly Alekseevich
Nizhny Tagil
Exploring Windows Presentation Foundation by Creating a To-Do List Application
At present, the problem of information visualization and the development of graphical interfaces is topical. This article describes the basics of using Windows Presentation Foundation (WPF) technology to create a graphical interface for a desktop application. The concept and features of WPF are highlighted, the possibilities of this technology are considered on the example of developing a simple application «To-Do list». A brief description and structure of the application being developed is given, the presentation of its visual part in the XAML markup language (MainWindow.xaml file) is analyzed in detail. Based on the obtained practical results of the work, it was concluded that there is a significant advantage of using WPF technology in development, which consists in the ability to separate the graphical interface of the application and its behavior from the internal logic of the program. The implementation of this feature leads to an increase in the efficiency of the architecture and performance of the developed application.
Keywords: learning programming environments, visual interface, desktop application, Windows Presentation Foundation, XAML markup language, Windows Presentation Foundation benefits.
В основе Windows Presentation Foundation (WPF) лежит векторная система визуализации, не зависящая от разрешения устройства вывода и созданная с учётом возможностей современного графического оборудования. Основной единицей измерения в графической системе WPF является аппаратно-независимый пиксель, который составляет 1/96 часть дюйма независимо от фактического разрешения экрана. WPF предоставляет средства для создания визуального интерфейса, включая язык XAML (eXtensible Application Markup Language), элементы управления, привязку данных, макеты, двухмерную и трёхмерную графику, анимацию, стили, шаблоны, документы, текст, мультимедиа и оформление [1].
Рассмотрим основные возможности WPF на примере создания однооконного приложения «Список дел» [2]. Суть работы приложения очень проста: пользователь записывает задачи, которые сохраняются в текстовом файле формата JSON. Также доступен просмотр актуальных и выполненных задач. Возможна пометка тегами и приоритетами для большей информативности.
Рис. 1. Диаграмма вариантов использования
Структура приложения в среде Visual Studio будет состоять из следующих элементов.
MainWindow.xaml – главное окно приложения.
TodoModel.cs – класс, в котором представлены поля для будущего отображения в объекте DataGrid
FileIOSevice.cs– класс, хранящий методы чтения и записи данных с JSON формата
App.xaml – файл с главными системными файлами, запускающие приложение.
Style TargetType – файл, который отвечает за установку стилей. Возвращает или задает тип, для которого предназначен данный стиль.
Setter — механизм установки, задающий значение свойства.
Style.Triggers — триггеры, которые следят за значением свойств объектов и в случае их изменения меняют эти свойства обращаясь к механизму Setter.
DataTrigger – триггеры, которые отслеживают изменение необязательных свойств объектов.
Подробнее разберем представление визуальной части приложения в файле MainWindow.xaml, фрагмент кода которого представлен в таблице 1.
Таблица 1
Создание формы главного окна приложения
Фрагмент кода |
Описание |
<Window x:Class=»TodoApp.MainWindow» Title=»Заметка» ResizeMode=»NoResize» Height=»450″ Width=»800″ WindowStartupLocation=»CenterScreen» Loaded=»Window_Loaded» Icon=»icon.png» <Window.Background> <ImageBrush ImageSource=»Grey.jpg»/> </Window.Background> |
Задание свойств окна приложения: — с фиксированным размером без возможности изменения размера по центру экрана; — иконка приложения, — загрузка фонового изображения она. |
<DataGrid.Columns> <DataGridTextColumn Binding=»{Binding Path = CreationDate}» IsReadOnly=»True» Header=»Дата» MinWidth=»90″ MaxWidth=»90″/> <DataGridCheckBoxColumn Binding=»{Binding Path = IsDone, UpdateSourceTrigger=PropertyChanged}» IsReadOnly=»False» Header=»ОК» MinWidth=»40″ MaxWidth=»40″/> <DataGridTextColumn Binding= «{Binding Path = Text}» IsReadOnly=»False» Header=»Список» Width=»*»/> </DataGrid.Columns> |
Задание свойств таблицы: — прозрачный фон; — поле «Дата», только для чтения (формируется автомаически); — чекбокс «ОК» для отметки задачи как выполненной; — поле таблицы для записи задач «Список» |
<StackPanel Orientation=»Horizontal» HorizontalAlignment=»Right»> <Image Name=»MinButton» Margin=»2,2,2,9″ Height=»33″ Width=»33″ MouseDown=»MinButton_MouseDown»> <Image.Style> <Style TargetType=»{x:Type Image}»> <Setter Property=»Source» Value=»Sourse/Minimize_Deactivate.png»/> <Style.Triggers> <DataTrigger Binding=»{Binding IsMouseOver, ElementName=MinButton}» Value=»True»> <Setter Property=»Source» Value=»Sourse/Minimize_Activated.png»/> </DataTrigger> </Style.Triggers> <Image Name=»CloseButton» Margin=»2,2,2,9″ Height=»33″ Width=»33″ MouseDown=»CloseButton_MouseDown»> |
Компоновка кнопок «Свернуть»/ «Развернуть/ «Закрыть» горизонтально в верхнем правом углу |
Как видно из фрагмента кода, подобно структуре веб-страницы на html в XAML есть некоторая иерархия элементов. Элементов верхнего уровня является объект Window, который представляет собой окно приложения. При создании других окон в приложении необходимо всегда начинать объявление интерфейса с элемента Window, поскольку это элемент самого верхнего уровня. Синтаксис любого объектного элемента начинается с левой угловой скобки ( < ), за которым следует сразу же имя типа класса или структуры, для которой создается экземпляр. В элементе Object могут быть объявлены ноль или более атрибутов с одним или несколькими пробелами, разделяющими каждую пару «имя атрибута =» значение «. Элемент и тег должны быть закрыты косой чертой (/), за которой следует правая угловая скобка (>).
Результат отображения главного окна приложения «Список дел», основанного на приведенной в таблице разметке приведен на рисунке 2.
Рис. 2. Главное окно приложения «Список дел»
Главное окно приложения запускает при старте входной точки приложения Main(), которая запускает инициализацию основных компонентов/методов приложения, а также инициализирует и создает графический интерфейс для приложения.
Преимущество использование WPF для создания графического интерфейса приложения заключается в большой гибкости: весь функционал графического интерфейса можно не писать в коде, а только в специальном коде XAML. Триггеры и привязка данных настраиваются без участия кода. Таким образом, можно полностью отделить графический интерфейс и его поведение от внутренней логики программы, что эффективно как для проектирования, так и для архитектуры приложения в целом.
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Мак-Дональд, М. WPF. Windows Presentation Foundation в .NET 4.5 с примерами на C# 5.0 для профессионалов / М. Мак-Дональд. – М.: Вильямс, 2013. – 1024 с. – Текст : непосредственный.
2. Создание простого приложения на C#. – Пошаговое руководство : электронное // https://docs.microsoft.com/ru-ru : [сайт]. – URL: https://docs.microsoft.com/ru-ru/visualstudio/get-started/csharp/tutorial-wpf?view=vs-2022 (дата обращения: 28.07.2021).
Windows Presentation Foundation (WPF) — аналог WinForms, система для построения клиентских приложений Windows с визуально привлекательными возможностями взаимодействия с пользователем, графическая (презентационная) подсистема в составе .NET Framework (начиная с версии 3.0), использующая язык XAML[1].
WPF предустановлена в Windows Vista (.NET Framework 3.0), Windows 7 (.NET Framework 3.5 SP1), Windows 8 (.NET Framework 4.0 и 4.5), Windows 8.1 (.NET Framework 4.5.1) и Windows 10 (.NET Framework 4.7). С помощью WPF можно создавать широкий спектр как автономных, так и запускаемых в браузере приложений[2].
Особенности технологии
В основе WPF лежит векторная система визуализации, не зависящая от разрешения устройства вывода и созданная с учётом возможностей современного графического оборудования. WPF предоставляет средства для создания визуального интерфейса, включая язык XAML (eXtensible Application Markup Language), элементы управления, привязку данных, макеты, двухмерную и трёхмерную графику, анимацию, стили, шаблоны, документы, текст, мультимедиа и оформление[2].
Графической технологией, лежащей в основе WPF, является DirectX, в отличие от Windows Forms, где используется GDI/GDI+[3]. Производительность WPF выше, чем у GDI+ за счёт использования аппаратного ускорения графики через DirectX.
Также существует урезанная версия CLR, называющаяся WPF/E, она же известна как Silverlight.
Использование разметки XAML
XAML представляет собой язык декларативного описания интерфейса, основанный на XML. Также реализована модель разделения кода и дизайна, позволяющая кооперироваться программисту и дизайнеру. Кроме того, есть встроенная поддержка стилей элементов, а сами элементы легко разделить на элементы управления второго уровня, которые, в свою очередь, разделяются до уровня векторных фигур и свойств/действий. Это позволяет легко задать стиль для любого элемента, например, Button (кнопка).
Средства разработки
Для работы с WPF требуется любой .NET-совместимый язык. В этот список входит множество языков: C#, F#, VB.NET, C++, Ruby, Python, Delphi (Prism), Lua и многие другие.
Для полноценной работы может быть использована как Visual Studio, так и Expression Blend. Первая ориентирована на программирование, а вторая — на дизайн и позволяет делать многие вещи, не прибегая к ручному редактированию XAML. Примеры этому — анимация, стилизация, состояния, создание элементов управления и так далее.
Возможности
WPF предоставляет широкий спектр возможностей по созданию интерактивных настольных приложений:
Привязка данных
Это гибкий механизм, который позволяет через расширения разметки XAML связывать различные данные (от значений свойств элементов управления до общедоступных свойств, реализующих поля базы данных через Entity Framework). Привязка данных представлена классом Binding, который в свою очередь унаследован от MarkupExtension, что позволяет использовать привязки не только в коде, но и в разметке:
<StackPanel Orientation="Horizontal"> <Slider x:Name="slider" Width="200" Minimum="1" Maximum="100" Value="60"/> <TextBox Text="{Binding ElementName=slider, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel>
Помимо основного класса Binding в WPF реализовано еще несколько механизмов привязок:
- MultiBinding — позволяет создавать множественные привязки, указывая несколько элементов
- TemplateBinding — используется в шаблонах для связывания свойства элемента внутри шаблона со свойством элемента, к которому применен шаблон
- PriorityBinding — ранжирует список привязок и выбирает из них свойство (согласно приоритету) к которому будет применена привязка. Если привязка, имеющая наивысший приоритет успешно возвращает значение, то нет необходимости обрабатывать другие привязки в списке.
Стили
Позволяют создавать стилевое оформление элементов и, как правило, используются только в разметке:
<Button> <Button.Style> <Style TargetType="Button"> <Setter Property="FontSize" Value="20"/> <Setter Property="Foreground" Value="LimeGreen"/> </Style> </Button.Style> </Button>
Если стиль задается в ресурсах (например в словаре ресурсов), то можно использовать атрибут x:Key для указания уникального ключа. Затем в элементе управления, к которому необходимо применить стиль, нужно использовать расширение разметки StaticResource для связывания с этим стилем. Если использовать этот прием, то стили не будут нагромождать разметку.
Шаблоны элементов управления
Позволяют менять графическое оформление элементов и представлены классом ControlTemplate. В отличие от стилей, можно менять не только графическое представление элемента, но и его структуру. При этом шаблон элемента управления задается через свойство Template.
Простой пример круглой кнопки:
<Button Content="Hey!" Background="LimeGreen" Foreground="White"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid> <Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" Stretch="Fill"/> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/> </Grid> </ControlTemplate> </Button.Template> </Button>
Шаблоны данных
В отличие от шаблонов элементов управления, задаются для определенного контекста данных (который в блочных элементах управления задается через свойство DataContext, а в списковых через ItemsSource). Сам шаблон данных представлен классом DataTemplate. Для обозначения типа данных, к которому необходимо применить шаблон, используется свойство DataType.
Ресурсы
Система ресурсов позволяет объединять шаблоны, стили, кисти, анимацию и многие другие интерактивные элементы, что существенно упрощает работу с ними. Ресурсы задаются в свойстве Resources класса FrameworkElement, от которого унаследованы все элементы управления, панели компоновки и даже класс Application. Это позволяет создавать многоуровневую систему ресурсов:
- ресурсы внутри объекта — действительны только для этого объекта
- ресурсы внутри панели компоновки (например Grid) — позволяет задать границу контекста ресурсов на уровне этой панели
- ресурсы внутри окна Window — если в приложении используется несколько окон, то ресурсы одного окна не будут доступны ресурсам другого окна
<Window.Resources> <SolidColorBrush x:Key="SampleBrush" Color="LimeGreen"/> </Window.Resources> ... <Button Content="Hey!" Background="{StaticResource SampleBrush}" />
- ресурсы приложения — доступны повсеместно (как правило задаются в отдельном словаре ресурсов)
Графика
WPF представляет обширный, масштабируемый и гибкий набор графических возможностей:
- Графика, не зависящая от разрешения и устройства. Основной единицей измерения в графической системе WPF является аппаратно-независимый пиксель, который составляет 1/96 часть дюйма независимо от фактического разрешения экрана.
- Дополнительная поддержка графики и анимации. WPF упрощает программирование графики за счет автоматического управления анимацией. Разработчик не должен заниматься обработкой сцен анимации, циклами отрисовки и билинейной интерполяцией
- Аппаратное ускорение. Графическая система WPF использует преимущества графического оборудования, чтобы уменьшить использование ЦП.
Двухмерная графика
WPF предоставляет библиотеку общих двухмерных фигур, нарисованных с помощью векторов, таких, как прямоугольники и эллипсы, а также графические пути. И в своей функциональности фигуры реализуют многие возможности, которые доступны обычным элементам управления.
Двухмерная графика в WPF включает визуальные эффекты, такие как градиенты, точечные рисунки, чертежи, рисунки с видео, поворот, масштабирование и наклон.
Трехмерная графика
WPF также включает возможности трехмерной отрисовки, интегрированные с двухмерной графикой, что позволяет создавать более яркий и интересный пользовательский интерфейс.
Версии
- WPF 3.0 (Ноябрь 2006)
- WPF 3.5 (Ноябрь 2007)
- WPF 3.5 SP1 (Август 2008)
- WPF 4 (Апрель 2010)
- WPF 4.5 (Август 2012)
- WPF 4.5.1 (Октябрь 2013)
- WPF 4.5.2 (Май 2014)
- WPF 4.6 (Июль 2015)
См. также
- Silverlight
- Windows Forms
- QML
Литература
- Мэтью Мак-Дональд. WPF: Windows Presentation Foundation в .NET 4.5 с примерами на C# 5.0 для профессионалов, 4-е издание = Pro WPF 4.5 in C# 2012: Windows Presentation Foundation in .NET 4.5, 4th edition. — М.: «Вильямс», 2013. — 1024 с. — ISBN 978-5-8459-1854-3.
- Мэтью Мак-Дональд. WPF: Windows Presentation Foundation в .NET 4.0 с примерами на C# 2010 для профессионалов = Pro WPF in C# 2010: Windows Presentation Foundation with .NET 4.0. — М.: «Вильямс», 2011. — С. 1024. — ISBN 978-5-8459-1657-0.
- Андерсон, Крис. Основы Windows Presentation Foundation. — СПб.: БХВ-Петербург, 2008. — 432 с. — ISBN 978-5-9775-0265-8.
- Daniel M. Solis. Illustrated WPF. — United States of America: Apress, 2009. — 508 с. — ISBN 978-1-4302-1910-1.
Ссылки
- MSDN Library — Windows Presentation Foundation
- Общие сведения о графике, анимации и мультимедиа WPF
Примечания
- ↑ Произносится как «замл»
- ↑ 2,0 2,1
MSDN. Введение в WPF. Microsoft. Дата обращения: 15 ноября 2010. Архивировано 14 февраля 2012 года. - ↑ Мэтью Мак-Дональд. WPF: Windows Presentation Foundation в .NET 3.5 с примерами на C# 2008 для профессионалов = Pro WPF in C# 2008: Windows Presentation Foundation with .NET 3.5. — 2-ое. — М.: «Вильямс», 2008. — С. 25. — 928 с. — ISBN 978-5-8459-1429-3.
Обзор типов оконных приложений в C#. Знакомство со структорой проекта WPF. Компоновка.
В C# есть несколько технологий для созданий оконных приложений:
-
Windows Forms — разработка «классических» приложений Windows (а-ля XP), считается устаревшей
Windows Forms — интерфейс программирования приложений (API), отвечающий за графический интерфейс пользователя и являющийся частью Microsoft .NET Framework. Данный интерфейс упрощает доступ к элементам интерфейса Microsoft Windows за счет создания обёртки для существующего Win32 API в управляемом коде. Причём управляемый код — классы, реализующие API для Windows Forms, не зависят от языка разработки.
-
WPF (Window Presentation Foundation) — основной фреймворк, на котором мы дальше и будем работать
-
UWP (Universal Windows Platform) — вроде как «последний писк», рассчитанный на разработку универсальных приложений под Windows Phone, Windows 8 и.т.д
Особенности платформы WPF
Если при создании традиционных приложений на основе WinForms за отрисовку элементов управления и графики отвечали такие части ОС Windows, как User32 и GDI+, то приложения WPF основаны на DirectX. В этом состоит ключевая особенность рендеринга графики в WPF: используя WPF, значительная часть работы по отрисовке графики, как простейших кнопочек, так и сложных 3D-моделей, ложиться на графический процессор на видеокарте, что также позволяет воспользоваться аппаратным ускорением графики.
Одной из важных особенностей является использование языка декларативной разметки интерфейса XAML, основанного на XML: вы можете создавать насыщенный графический интерфейс, используя или декларативное объявление интерфейса, или код на управляемых языках C# и VB.NET, либо совмещать и то, и другое.
Преимущества WPF
Что вам, как разработчику, предлагает WPF?
-
Использование традиционных языков .NET-платформы — C# и VB.NET для создания логики приложения
-
Возможность декларативного определения графического интерфейса с помощью специального языка разметки XAML, основанном на xml и представляющем альтернативу программному созданию графики и элементов управления, а также возможность комбинировать XAML и C#/VB.NET
-
Независимость от разрешения экрана: поскольку в WPF все элементы измеряются в независимых от устройства единицах, приложения на WPF легко масштабируются под разные экраны с разным разрешением.
-
Новые возможности, которых сложно было достичь в WinForms, например, создание трехмерных моделей, привязка данных, использование таких элементов, как стили, шаблоны, темы и др.
-
Хорошее взаимодействие с WinForms, благодаря чему, например, в приложениях WPF можно использовать традиционные элементы управления из WinForms.
-
Богатые возможности по созданию различных приложений: это и мультимедиа, и двухмерная и трехмерная графика, и богатый набор встроенных элементов управления, а также возможность самим создавать новые элементы, создание анимаций, привязка данных, стили, шаблоны, темы и многое другое
-
Аппаратное ускорение графики — вне зависимости от того, работаете ли вы с 2D или 3D, графикой или текстом, все компоненты приложения транслируются в объекты, понятные Direct3D, и затем визуализируются с помощью процессора на видеокарте, что повышает производительность, делает графику более плавной.
Создание оконного приложения
Запустите Microsoft Visual Studio (MVS) и создайте новое приложение:
Тип приложения: WPF (.NET Framework)
При создании задаете Имя проекта и, если нужно, Расположение. Остальные параметры оставляем по-умолчанию.
Название проекта должно отражать предметную область или название компании (за это есть отдельные баллы на WorldSkills-е и демо-экзамене)
По-умолчанию IDE Visual Studio разбито на 3 части:
- слева панель элементов — список визуальных элементов (кнопки, токстовые поля и т.п.)
- в центре основное окно, предназначенное для редактирования исходного кода. При отображении файлов XAML (читается как «замл») разбито на две части: визуальное отображение и текст разметки
- справа Обозреватель решений и структура проекта: Properties (Свойства); Ссылки (Зависимости); App.config — настройки проекта; App.xaml — разметка проекта и MainWindow.xaml — разметка окна.
Если каких-то панелей нет на экране, то можно их найти в меню Вид.
Основные типы файлов проекта:
- .XAML eXtended Application Markup Languale — язык разметки, очень похож на XML. В таких файлах хранится описание внешнего вида окна.
- .cs — файлы с исходным кодом на C# для окна.
Структура проекта
В структуре проекта WPF следует выделить следующие моменты. Во-первых, в проекте имеется файл App.xaml
и связанный с ним файл кода App.xaml.cs
— это глобальные файлы для всего приложения, позже мы о них поговорим подробнее. А пока только следует знать, что App.xaml
задает файл окна программы, которое будет открываться при запуске приложения. Если вы откроете этот файл, то можете найти в нем строку StartupUri="MainWindow.xaml"
— то есть в данном случае, когда мы запустим приложение, будет создаваться интерфейс из файла MainWindow.xaml
.
Далее в структуре определены файл разметки MainWindow.xaml
и файл связанного кода MainWindow.xaml.cs
. Файл MainWindow.xaml
и представляет определение окна приложение, которое мы увидим при запуске.
Введение в язык XAML
XAML (eXtensible Application Markup Language) — язык разметки, используемый для инициализации объектов в технологиях на платформе .NET. Применительно к WPF данный язык используется прежде всего для создания пользовательского интерфейса декларативным путем, наподобие HTML в веб-программировании.
XAML — не является обязательной частью приложения, мы вобще можем обходиться без него, создавая все элементы в файле связанного с ним кода на языке C#. Однако использование XAML все-таки несет некоторые преимущества:
-
Возможность отделить графический интерфейс от логики приложения, благодаря чему над разными частями приложения могут относительно автономно работать разные специалисты: над интерфейсом — дизайнеры, над кодом логики — программисты.
-
Компактность, понятность, код на XAML относительно легко поддерживать.
При компиляции приложения в Visual Studio код в xaml-файлах также компилируется в бинарное представление кода xaml, которое называется BAML (Binary Application Markup Language). И затем код baml встраивается в финальную сборку приложения — exe или dll-файл.
Структура и пространства имен XAML
При создании нового проекта WPF он уже содержит файлы с кодом xaml. Так, создаваемый по умолчанию в проекте файл MainWindow.xaml
будет иметь следующую разметку:
<Window x:Class="XamlApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XamlApp" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>
Если вы совершенно не знакомы с xaml и с xml, то даже этот небольшой минимальный код окна может вызывать затруднения.
Подобно структуре веб-страничке на html, здесь есть некоторая иерархия элементов. Элементов верхнего уровня является Window, который представляет собой окно приложения. При создании других окон в приложении нам придется всегда начинать объявление интерфейса с элемента Window, поскольку это элемент самого верхнего уровня.
Кроме Window существует еще два элемента верхнего уровня:
- Page
- Application
Элемент Window имеет вложенный пустой элемент Grid, а также подобно html-элементам ряд атрибутов (Title, Width, Height) — они задают заголовок, ширину и высоту окна соответственно.
Пространства имен XAML
При создании кода на языке C#, чтобы нам были доступны определенные классы, мы подключаем пространства имен с помощью директивы using, например, using System.Windows;
.
Чтобы задействовать элементы в XAML, мы также подключаем пространства имен. Вторая и третья строчки как раз и представляют собой пространства имен, подключаемые в проект по умолчанию. А атрибут xmlns представляет специальный атрибут для определения пространства имен в XML.
Так, пространство имен http://schemas.microsoft.com/winfx/2006/xaml/presentation содержит описание и определение большинства элементов управления. Так как является пространством имен по умолчанию, то объявляется без всяких префиксов.
http://schemas.microsoft.com/winfx/2006/xaml — это пространство имен, которое определяет некоторые свойства XAML, например свойство Name или Key. Используемый префикс x в определении xmlns:x означает, что те свойства элементов, которые заключены в этом пространстве имен, будут использоваться с префиксом x — x:Name или x:Key. Это же пространство имен используется уже в первой строчке x:Class=»XamlApp.MainWindow» — здесь создается новый класс MainWindow и соответствующий ему файл кода, куда будет прописываться логика для данного окна приложения.
Это два основных пространства имен. Рассмотрим остальные:
xmlns:d=»http://schemas.microsoft.com/expression/blend/2008″: предоставляет поддержку атрибутов в режиме дизайнера. Это пространство имен преимущественно предназначено для другого инструмента по созданию дизайна на XAML — Microsoft Expression Blend
xmlns:mc=»http://schemas.openxmlformats.org/markup-compatibility/2006″: обеспечивает режим совместимости разметок XAML. В определении объекта Window двумя строчками ниже можно найти его применение:
xmlns:local=»clr-namespace:XamlApp»: пространство имен текущего проекта. Так как в нашем случае проект называется XamlApp, то простраство имен называется аналогично. И через префикс local я смогу получить в XAML различные объекты, которые я определил в проекте.
Важно понимать, что эти пространства имен не эквивалентны тем пространствам имен, которые подключаются при помощи директивы using в c#.
Элементы и их атрибуты
XAML предлагает очень простую и ясную схему определения различных элементов и их свойств. Каждый элемент, как и любой элемент XML, должен иметь открытый и закрытый тег, как в случае с элементом Window:
Либо элемент может иметь сокращенню форму с закрывающим слешем в конце, наподобие:
Но в отличие от элементов xml каждый элемент в XAML соответствует определенному классу C#. Например, элемент Button соответствует классу System.Windows.Controls.Button. А свойства этого класса соответствуют атрибутам элемента Button.
Например, добавим кнопку в создаваемую по умолчанию разметку окна:
<Window x:Class="XamlApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XamlApp" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid x:Name="grid1"> <Button x:Name="button1" Width="100" Height="30" Content="Кнопка" /> </Grid> </Window>
Сначала идет элемент самого высшего уровня — Window, затем идет вложенный элемент Grid — контейнер для других элементов, и в нем уже определен элемент Button, представляющий кнопку.
Для кнопки мы можем определить свойства в виде атрибутов. Здесь определены атрибуты x:Name (имя кнопки), Width, Height и Content. Причем, атрибут x:Name берется в данном случае из пространства имен «http://schemas.microsoft.com/winfx/2006/xaml», которое сопоставляется с префиксом x. А остальные атрибуты не используют префиксы, поэтому берутся из основного пространства имен «http://schemas.microsoft.com/winfx/2006/xaml/presentation».
Подобным образом мы можем определить и другие атрибуты, которые нам нужны. Либо мы в общем можем не определять атрибуты, и тогда они будут использовать значения по умолчанию.
Определив разметку xaml, мы можем запустить проект, и нам отобразится графически весь код xaml — то есть наша кнопка.
Специальные символы
При определении интерфейса в XAML мы можем столкнуться с некоторыми ограничениями. В частости, мы не можем использовать специальные символы, такие как знак амперсанда &, кавычки » и угловые скобки < и >. Например, мы хотим, чтобы текст кнопки был следующим: <"Hello">
. У кнопки есть свойство Content, которое задает содержимое кнопки. И можно предположить, что нам надо написать так:
<Button Content="<"Hello">" />
Но такой вариант ошибочен и даже не скомпилирутся. В этом случае нам надо использовать специальные коды символов:
Символ | Код |
---|---|
< |
< |
> |
> |
& | & |
« | " |
Например:
<Button Content="<"Hello">" />
Еще одна проблема, с которой мы можем столкнуться в XAML — добавление пробелов. Возьмем, к примеру, следующее определение кнопки:
<Button> Hello World </Button>
Здесь свойство Content задается неявно в виде содержимого между тегами <Button>....</Button>
. Но несмотря на то, что у нас несколько пробелов между словами «Hello» и «World», XAML по умолчанию будет убирать все эти пробелы. И чтобы сохранить пробелы, нам надо использовать атрибут xml:space="preserve"
:
<Button xml:space="preserve"> Hello World </Button>
Файлы отделенного кода
При создании нового проекта WPF в дополнение к создаваемому файлу MainWindow.xaml
создается также файл отделенного кода MainWindow.xaml.cs
, где, как предполагается, должна находится логика приложения связанная с разметкой из MainWindow.xaml
. Файлы XAML позволяют нам определить интерфейс окна, но для создания логики приложения, например, для определения обработчиков событий элементов управления, нам все равно придется воспользоваться кодом C#.
По умолчанию в разметке окна используется атрибут x:Class
:
<Window x:Class="XamlApp.MainWindow" .......
Атрибут x:Class
указывает на класс, который будет представлять данное окно и в который будет компилироваться код в XAML при компиляции. То есть во время компиляции будет генерироваться класс XamlApp.MainWindow, унаследованный от класса System.Windows.Window.
Кроме того в файле отделенного кода MainWindow.xaml.cs
, который Visual Studio создает автоматически, мы также можем найти класс с тем же именем — в данном случае класс XamlApp.MainWindow. По умолчанию он имеет некоторый код:
namespace XamlApp { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } }
По сути пустой класс, но этот класс уже выполняет некоторую работу. Во время компиляции этот класс объединяется с классом, сгенерированном из кода XAML. Чтобы такое слияние классов во время компиляции произошло, класс XamlApp.MainWindow определяется как частичный с модификатором partial. А через метод InitializeComponent() класс MainWindow вызывает скомпилированный ранее код XAML, разбирает его и по нему строит графический интерфейс окна.
Взаимодействие кода C# и XAML
В приложении часто требуется обратиться к какому-нибудь элементу управления. Для этого надо установить у элемента в XAML свойство Name.
Еще одной точкой взаимодействия между xaml и C# являются события. С помощью атрибутов в XAML мы можем задать события, которые будут связанны с обработчиками в коде C#.
Итак, создадим новый проект WPF, который назовем XamlApp. В разметке главного окна определим два элемента: кнопку и текстовое поле.
<Grid x:Name="grid1"> <TextBox x:Name="textBox1" Width="150" Height="30" VerticalAlignment="Top" Margin="20" /> <Button x:Name="button1" Width="100" Height="30" Content="Кнопка" Click="Button_Click" /> </Grid>
И изменим файл отделенного кода, добавив в него обработчик нажатия кнопки:
namespace XamlApp { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { string text = textBox1.Text; if (text != "") { MessageBox.Show(text); } } } }
Определив имена элементов в XAML, затем мы можем к ним обращаться в коде c#: string text = textBox1.Text
.
В обработчике нажатия кнопки просто выводится сообщение , введенное в текстовое поле. После определения обработчика мы его можем связать с событием нажатия кнопки в xaml через атрибут Click: Click="Button_Click"
. В результате после нажатия на кнопку мы увидим в окне введенное в текстовое поле сообщение.
Пространства имен из C# в XAML
По умолчанию в WPF в XAML подключается предустановленный набор пространств имен xml. Но мы можем задействовать любые другие пространства имен и их функциональность в том числе и стандартные пространства имен платформы .NET, например, System или System.Collections. Например, по умолчанию в определении элемента Window подключается локальное пространство имен:
xmlns:local="clr-namespace:XamlApp"
Локальное пространство имен, как правило, называется по имени проекта (в моем случае проект называется XamlApp) и позволяет подключить все классы, которые определены в коде C# в нашем проекте. Например, добавим в проект следующий класс:
public class Phone { public string Name { get; set; } public int Price { get; set; } public override string ToString() { return $"Смартфон {this.Name}; цена: {this.Price}"; } }
Используем этот класс в коде xaml:
<Grid x:Name="layoutGrid"> <Button x:Name="phoneButton" Width="250" Height="40" HorizontalAlignment="Center"> <Button.Content> <local:Phone Name="Lumia 950" Price="700" /> </Button.Content> </Button> </Grid>
Так как пространство имен проекта проецируется на префикс local, то все классы проекта используются в форме local:Название_Класса
. Так в данном случае объект Phone устанавливается в качестве содержимого кнопки через свойство Content. Для сложных объектов это свойство принимает их строковое представление, которое возвращается методом ToString().
Мы можем подключить любые другие пространства имен, классы которых мы хотим использовать в приложении. Например:
<Window x:Class="XamlApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XamlApp" xmlns:col="clr-namespace:System.Collections;assembly=mscorlib" xmlns:sys="clr-namespace:System;assembly=mscorlib" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <col:ArrayList x:Key="days"> <sys:String>Понедельник</sys:String> <sys:String>Вторник</sys:String> <sys:String>Среда</sys:String> <sys:String>Четверг</sys:String> <sys:String>Пятница</sys:String> <sys:String>Суббота</sys:String> <sys:String>Воскресенье</sys:String> </col:ArrayList> </Window.Resources> <Grid> </Grid> </Window>
Здесь определены два дополнительных пространства имен:
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Благодаря этому нам становятся доступными объекты из пространств имен System.Collections и System. И затем используя префикс, мы можем использовать объекты, входящие в данные пространства имен: <col:ArrayList....
Общий синтаксис подключения пространств имен следующий: xmlns:Префикс="clr-namespace:Пространство_имен;assembly=имя_сборки"
. Так в предыдущем случае мы подключили пространство имен System.Collections, классы которого находятся в сборке mscorlib. И данное подключенное пространство имен у нас отображено на префикс col.
Компоновка
Чтобы перейти уже непосредственно к созданию красивых интерфейсов и их компонентов, сначала необходимо познакомиться с компоновкой. Компоновка (layout) представляет собой процесс размещения элементов внутри контейнера. Возможно, вы обращали внимание, что одни программы и веб-сайты на разных экранах с разным разрешением выглядят по-разному: где-то лучше, где-то хуже. В большинстве своем такие программы используют жестко закодированные в коде размеры элементов управления. WPF уходит от такого подхода в пользу так называемого «резинового дизайна», где весь процесс позиционирования элементов осуществляется с помощью компоновки.
Благодаря компоновке мы можем удобным нам образом настроить элементы интерфейса, позиционировать их определенным образом. Например, элементы компоновки в WPF позволяют при ресайзе — сжатии или растяжении масштабировать элементы, что очень удобно, а визуально не создает всяких шероховатостей типа незаполненных пустот на форме.
В WPF компоновка осуществляется при помощи специальных контейнеров. Фреймворк предоставляет нам следующие контейнеры: Grid, UniformGrid, StackPanel, WrapPanel, DockPanel и Canvas.
Различные контейнеры могут содержать внутри себя другие контейнеры. Кроме данных контейнеров существует еще ряд элементов, такие как TabPanel, которые могут включать другие элементы и даже контейнеры компоновки, однако на саму компоновку не столь влияют в отличие от выше перечисленных. Кроме того, если нам не хватает стандартных контейнеров, мы можем определить свои с нужной нам функциональностью.
Контейнеры компоновки позволяют эффективно распределить доступное пространство между элементами, найти для него наиболее предпочтительные размеры.
В WPF при компоновке и расположении элементов внутри окна нам надо придерживаться следующих принципов:
-
Нежелательно указывать явные размеры элементов (за исключеним минимальных и максимальных размеров). Размеры должны определяться контейнерами.
-
Нежелательно указывать явные позицию и координаты элементов внутри окна. Позиционирование элементов всецело должно быть прерогативой контейнеров. И контейнер сам должен определять, как элемент будет располагаться. Если нам надо создать сложную систему компоновки, то мы можем вкладывать один контейнер в другой, чтобы добиться максимально удобного расположения элементов управления.
Grid
Это наиболее мощный и часто используемый контейнер, напоминающий обычную таблицу. Он содержит столбцы и/или строки, количество которых задает разработчик. Для определения строк используется свойство RowDefinitions, а для определения столбцов — свойство ColumnDefinitions:
<Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> </Grid>
Можно писть это в разметке, но можно просто кликнуть мышкой по границе Grid-а:
Каждая строка задается с помощью вложенного элемента RowDefinition, который имеет открывающий и закрывающий тег. При этом задавать дополнительную информацию необязательно. То есть в данном случае у нас определено в гриде 3 строки.
Каждая столбец задается с помощью вложенного элемента ColumnDefinition. Таким образом, здесь мы определили 3 столбца. ТО есть в итоге у нас получится таблица 3х3.
Чтобы задать позицию элемента управления с привязкой к определенной ячейке Grid-а, в разметке элемента нужно прописать значения свойств Grid.Column и Grid.Row, тем самым указывая, в каком столбце и строке будет находиться элемент. Кроме того, если мы хотим растянуть элемент управления на несколько строк или столбцов, то можно указать свойства Grid.ColumnSpan и Grid.RowSpan, как в следующем примере:
<Window x:Class="LayoutApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LayoutApp" mc:Ignorable="d" Title="Grid" Height="250" Width="350"> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Button Grid.Column="0" Grid.Row="0" Content="Строка 0 Столбец 0" /> <Button Grid.Column="0" Grid.Row="1" Content="Объединение трех столбцов" Grid.ColumnSpan="3" /> <Button Grid.Column="2" Grid.Row="2" Content="Строка 2 Столбец 2" /> </Grid> </Window>
Атрибут ShowGridLines=»True» у элемента Grid задает видимость сетки, по умолчанию оно равно False.
То есть у нас получится следующая картина:
Установка размеров
Но если в предыдущем случае у нас строки и столбцы были равны друг другу, то теперь попробуем их настроить столбцы по ширине, а строки — по высоте. Есть несколько вариантов настройки размеров.
Автоматические размеры
Здесь столбец или строка занимает то место, которое им нужно
<ColumnDefinition Width="Auto" /> <RowDefinition Height="Auto" />
Абсолютные размеры
В данном случае высота и ширина указываются в единицах, независимых от устройства:
<ColumnDefinition Width="150" /> <RowDefinition Height="150" />
Также абсолютные размеры можно задать в пикселях, дюймах, сантиметрах или точках:
- пиксели: px
- дюймы: in
- сантиметры: cm
- точки: pt (точка в вёрстке это не точка на экране, а 1/72 дюйма)
Например,
<ColumnDefinition Width="1 in" /> <RowDefinition Height="10 px" />
Пропорциональные размеры.
Например, ниже задаются два столбца, второй из которых имеет ширину в четверть от ширины первого:
<ColumnDefinition Width="*" /> <ColumnDefinition Width="0.25*" />
Если строка или столбец имеет высоту, равную *
, то данная строка или столбце будет занимать все оставшееся место. Если у нас есть несколько сток или столбцов, высота которых равна *
, то все доступное место делится поровну между всеми такими сроками и столбцами. Использование коэффициентов (0.25*
) позволяет уменьшить или увеличить выделенное место на данный коэффициент. При этом все коэффициенты складываются (коэффициент *
аналогичен 1*
) и затем все пространство делится на сумму коэффициентов.
Например, если у нас три столбца:
<ColumnDefinition Width="*" /> <ColumnDefinition Width="0.5*" /> <ColumnDefinition Width="1.5*" />
В этом случае сумма коэффициентов равна 1* + 0.5* + 1.5* = 3*
. Если у нас грид имеет ширину 300 единиц, то для коэфициент 1*
будет соответствовать пространству 300 / 3 = 100 единиц. Поэтому первый столбец будет иметь ширину в 100 единиц, второй — 100*0.5=50 единиц, а третий — 100 * 1.5 = 150 единиц.
Можно комбинировать все типы размеров. В этом случае от ширины/высоты грида отнимается ширина/высота столбцов/строк с абсолютными или автоматическими размерами, и затем оставшееся место распределяется между столбцами/строками с пропорциональными размерами:
GridSplitter
Элемент GridSplitter помогает создавать интерфейсы наподобие элемента SplitContainer в WinForms, только более функциональные. Он представляет собой некоторый разделитель между столбцами или строками, путем сдвига которого можно регулировать ширину столбцов и высоту строк. В качестве примера можно привести стандартный интерфейс проводника в Windows, где разделительная полоса отделяет древовидный список папок от панели со списком файлов. Например,
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Grid.Column="0" Content="Левая кнопка" /> <GridSplitter Grid.Column="1" ShowsPreview="False" Width="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" /> <Button Grid.Column="2" Content="Правая кнопка" /> </Grid>
Двигая центральную линию, разделяющую правую и левую части, мы можем устанавливать их ширину.
Итак, чтобы использовать элемент GridSplitter, нам надо поместить его в ячейку в Gride. По сути это обычный элемент, такой же, как кнопка. Как выше, у нас три ячейки (так как три столбца и одна строка), и GridSplitter помещен во вторую ячейку. Обычно строка или столбец, в которые помещают элемент, имеет для свойств Height или Width значение Auto.
Если у нас несколько строк, и мы хотим, чтобы разделитель распространялся на несколько строк, то мы можем задать свойство Grid.RowSpan:
<Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <GridSplitter Grid.Column="1" Grid.RowSpan="2" ShowsPreview="False" Width="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" />
В случае, если мы задаем горизонтальный разделитель, то тогда соответственно надо использовать свойство Grid.ColumnSpan
Затем нам надо настроить свойства. Во-первых, надо настроить ширину (Width) для вертикальных сплитеров и высоту (Height) для горизонтальных. Если не задать соответствующее свойство, то сплитер мы не увидим, так как он изначально очень мал.
Затем нам надо задать выравнивание. Если мы хотим, что сплитер заполнял всю высоту доступной области (то есть если у нас вертикальный сплитер), то нам надо установить для свойства VerticalAlignment значение Stretch.
Если же у нас горизонтальный сплитер, то надо установить свойство HorizontalAlignment в Stretch
Также в примере выше используется свойство ShowsPreview. Если оно равно False, то изменение границ кнопок будет происходить сразу же при перемещении сплитера. Если же оно равно True, тогда изменение границ будет происходить только после того, как перемещение сплитера завершится, и при перемещении сплиттера мы увидим его проекцию.
StackPanel
Это более простой элемент компоновки. Он располагает все элементы в ряд либо по горизонтали, либо по вертикали в зависимости от ориентации. Например,
<Grid> <StackPanel> <Button Background="Blue" Content="1" /> <Button Background="White" Content="2" /> <Button Background="Red" Content="3" /> </StackPanel> </Grid>
В данном случае для свойства Orientation по умолчанию используется значение Vertical, то есть StackPanel создает вертикальный ряд, в который помещает все вложенные элементы сверху вниз. Мы также можем задать горизонтальный стек. Для этого нам надо указать свойство Orientation=»Horizontal»:
<StackPanel Orientation="Horizontal"> <Button Background="Blue" MinWidth="30" Content="1" /> <Button Background="White" MinWidth="30" Content="2" /> <Button Background="Red" MinWidth="30" Content="3" /> </StackPanel>
При горизонтальной ориентации все вложенные элементы располагаются слева направо. Если мы хотим, чтобы наполнение стека начиналось справа налево, то нам надо задать свойство FlowDirection: <StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
. По умолчанию это свойство имеет значение LeftToRight — то есть слева направо.
WrapPanel
Эта панель, подобно StackPanel, располагает все элементы в одной строке или колонке в зависимости от того, какое значение имеет свойство Orientation — Horizontal или Vertical. Главное отличие от StackPanel — если элементы не помещаются в строке или столбце, создаются новые столбец или строка для не поместившихся элементов.
<Window x:Class="LayoutApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LayoutApp" mc:Ignorable="d" Title="WrapPanel" Height="250" Width="300"> <WrapPanel> <Button Background="AliceBlue" Content="Кнопка 1" /> <Button Background="Blue" Content="Кнопка 2" /> <Button Background="Aquamarine" Content="Кнопка 3" Height="30"/> <Button Background="DarkGreen" Content="Кнопка 4" Height="20"/> <Button Background="LightGreen" Content="Кнопка 5"/> <Button Background="RosyBrown" Content="Кнопка 6" Width="80" /> <Button Background="GhostWhite" Content="Кнопка 7" /> </WrapPanel> </Window>
В горизонтальном стеке те элементы, у которых явным образом не установлена высота, будут автоматически принимать высоту самого большого элемента из стека.
Вертикальный WrapPanel делается аналогично:
<WrapPanel Orientation="Vertical"> <Button Background="AliceBlue" Content="Кнопка 1" Height="50" /> <Button Background="Blue" Content="Кнопка 2" /> <Button Background="Aquamarine" Content="Кнопка 3" Width="60"/> <Button Background="DarkGreen" Content="Кнопка 4" Width="80"/> <Button Background="LightGreen" Content="Кнопка 5"/> <Button Background="RosyBrown" Content="Кнопка 6" Height="80" /> <Button Background="GhostWhite" Content="Кнопка 7" /> <Button Background="Bisque" Content="Кнопка 8" /> </WrapPanel>
В вертикальном стеке элементы, у которых явным образом не указана ширина, автоматически принимают ширину самого широкого элемента.
Мы также можем установить для всех вложенных элементов какую-нибудь определенную ширину (с помощью свойства ItemWidth) или высоту (свойство ItemHeight):
<WrapPanel ItemHeight="30" ItemWidth="80" Orientation="Horizontal"> <Button Background="AliceBlue" Content="1" /> <Button Background="Blue" Content="2" /> <Button Background="Aquamarine" Content="3"/> <Button Background="DarkGreen" Content="4"/> <Button Background="LightGreen" Content="5"/> <Button Background="AliceBlue" Content="6" /> <Button Background="Blue" Content="7" /> </WrapPanel>
Image
Для добавления ресурсов в проект можно создать в нём каталог (кликнуть правой кнопкой мышки на название проекта и выбрать Добавить — Создать папку) и скопировать в него нужный ресурс, в нашем случае картинку.
Обратите внимание, копировать нужно именно в интерфейсе Visual Studio, а не средствами ОС, иначе VS будет искать ресурс не в папке проекта, а в текущей папке VS.
И добавим картинку в сетку:
... <Image Source="./img/simon.png" VerticalAlignment="Top"/> </Grid>
Атрибут VerticalAlignment устанавливает вертикальное выравнивание элемента относительно предка (Grid-а).
Атрибут Grid.ColumnSpan (есть и RowSpan) позволяет разместить элемент не в одной ячейке Grid-a, а «размазать» на несколько. Например, можно сделать фоновую картинку (как в примере ниже) или горизонтальное меню в верхней строке.
<Image Source="./img/simon.png" VerticalAlignment="Top" Grid.ColumnSpan="3"/>
Аннотация
Рассматриваются вопросы разработки приложения на основе
технологии WPF. Начальными фазами разработки является проектирование главной
страницы приложения, формирование градиентной заливки фона страницы,
организация навигации по страницам, формирование меню, панели команд,
формирование сетки для данных DataGrid,
создание команд страницы для работы с сотрудниками предприятия и управление
доступностью команд.
Цель
Освоить основные приемы разработки WPF-приложений на основе страничной организации приложения, создания меню,
панели команд, табличных элементов управления и системы команд для выполнения
задач приложения.
1.
Создание приложения
Как правило, корпоративное приложение представляет собой программу, реализующую
определенную бизнес-задачу (бизнес-функцию). Приложение должно
взаимодействовать с данными, которые располагаются в базе данных информационной
системы. Архитектура приложения обычно включает слой
представления, бизнес-логики и данных. Функциональность каждого слоя приложения
во многом определяется предметной областью информационной системы, но имеются и
общие, основополагающие функции, которые присущи практически любому
корпоративному приложению. Так в приложении необходимо разработать слой
представления, который обеспечит интерфейс пользователя с
системой. Интерфейс может
быть создан с использованием Windows окон и страниц WPF,
которые наполняются различными визуальными элементами контроля. Элементы
контроля должны поддерживать визуальное представление функциональности
системы для пользователя, проводить верификацию вводимых данных и
взаимодействовать с бизнес-классами. Слой
бизнес-логики приложения должен обеспечивать основную функциональность
приложения: формировать бизнес-классы, реализовывать алгоритмы обработки
данных, обеспечивать соединение с данными и их кэширование.
Реализация данного слоя приложения может быть построена на базе классов,
реализующих бизнес-логику, методами классов интерфейсных элементов или методами
классов модели данных. Слой данных должен
обеспечить взаимодействие приложения с данными системы
управления базами данных. В корпоративных приложениях для этого наиболее
целесообразно использовать платформу ADO.NET Entity Framework и модель EDM (Entity
Data Model). Модель EDM описывает структуру данных независимо от формы
хранения.
Для изучения вопросов проектирования корпоративных
приложений рассмотрим основные подходы при разработке отдельной функции
информационной системы, которая обеспечивает обработку данных по сотрудникам компании. Для учебного примера
используется база данных TitlePersonal с небольшим
набором таблиц и полей, а функциональность приложения предполагает обеспечение
ввода, корректировки и удаление данных о сотрудниках компании. Разрабатываемое
приложение должно обеспечивать хранение и обработку
следующих данных по сотрудникам компании: фамилия; имя;
отчество; должность; дата рождения; телефон; адрес электронной
почты.
Функции приложения:
1.
просмотр данных по сотрудникам;
2.
ввод данных по новому сотруднику;
3.
редактирование данных по сотруднику;
4.
удаление данных по сотруднику;
5.
поиск данных по сотруднику.
Для разработки приложения необходимо создать WPF-проект
(Рисунок
1).
В окне «Создать проект» необходимо проверить установку библиотеки .NET
Framework 4 (1 – на Рисунок 1),
выбрать шаблоны Windows (2 –
на Рисунок 1),
а среди имеющихся шаблонов задать Приложение WPF
и в поле «Имя» ввести имя проекта WPF_FIO
(где FIO — ваша фамилия).
Рисунок 1. Окно создания проекта
После нажатия кнопки «ОК» будет сформирован шаблон проекта. При этом инструментальная система
сгенерирует следующий XAML-документ:
<Window x:Class=»Wpf_Erina.MainWindow»
xmlns=»http://schemas.microsoft.com/winfx/2006/xaml/presentation»
xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml»
Title=»MainWindow»
Height=»350″ Width=»525″>
<Grid>
</Grid>
</Window>
Дизайнер
проекта приведен на Рисунок 2.
Рисунок 2. Окно дизайнера проекта
В приведенном XAML-документе имеется
один элемент верхнего уровня <Window>.
Дескриптор </Window> завершает весь документ. В XAML-документе
приведено имя класса MainWindow
x:Class=»Wpf_Erina.MainWindow»
два пространства имен
xmlns=»http://schemas.microsoft.com/winfx/2006/xaml/presentation«
xmlns:x=»http://schemas.microsoft.com/winfx/2006/xaml«
и три свойства:
Title=»MainWindow»
Height=»350″ Width=»525″
Каждый атрибут
соответствует определенному свойству класса Window. Приведенные атрибуты предписывают
WPF создать окно с надписью MainWindow и размером 350х525 единиц. При компиляции и запуске проекта
приложения на дисплей выводится окно, приведенное на Рисунок 3.
Рисунок 3. Окно MainWindow проекта
Когда выполняется компиляция приложения,
XAML-файл, который определяет пользовательский интерфейс (MainWindow.xaml), транслируется в
объявление типа CLR , которое объединяется с логикой
приложения из файла класса отдельного кода (MainWindow.xaml.cs).
Метод InitializeComponent() генерируется во время компиляции приложения
и в исходном коде не присутствует.
Для программного управления элементами управления,
описанными в XAML-документе, необходимо задать XAML атрибут Name. Так для задания имени элементу Grid необходимо
записать следующую разметку:
<Grid Name=»grid»>
</Grid>
2.
Формирование начальной страницы приложения
В последнее время разработчики корпоративных приложений
начали осознавать преимущества технологий веб-дизайна, которые базируются на качественном
дизайне, четком и понятном интерфейсе. Технология WPF позволяет создавать страничную модель (приложения),
с готовыми средствами навигации. Как правило, для
каждой страницы приложения создается файл XAML и файл отдельного кода, например
на языке C#. При компиляции такого приложения компилятор создает производный класс страницы,
который объединяет написанный код с генерируемыми автоматически связующими
элементами.
Страницы можно размещать внутри окон и внутри других
страниц. В WPF при создании страничных приложений контейнером наивысшего уровня
могут быть следующие объекты:
1.
NavigationWindow,
который представляет собой несколько видоизмененную версию класса Window;
2.
Frame,
находящийся внутри другого окна или другой страницы;
3.
Frame,
обслуживаемый непосредственно в Internet Explorer.
Для вставки страницы внутрь окна будем использовать класс Frame (Рисунок
4).
Автоматически будет сгенерирован экземпляр класса Frame с
фиксированными границами (Рисунок
5).
Рисунок 4. Выбор класса Frame в панели инструментов
Рисунок 5. Фрейм с фиксированными границами
В XAML-документ проекта будет
добавлена следующая строка:
<Frame Content=»Frame» HorizontalAlignment=»Left» Height=»100″
Margin=»144,95,0,0″
VerticalAlignment=»Top» Width=»100″/>
С учетом того, что создается
страничное приложение размеры фрейма не нужно
фиксировать, поэтому изменим описание свойств фрейма:
<Frame Name =»frame1″ Margin=»3″ />
В результате фрейм
заполнит всё окно (Рисунок
6):
Рисунок 6. Фрейм, заполняющий всё окно
Созданный фрейм необходим для
размещения в нем страницы WPF-приложения. Класс Page допускает
наличие только одного вложенного элемента. Он не является элементом управления
содержимым и наследуется от класса FrameworkElement.
Класс Page имеет небольшой набор дополнительных свойств, которые
позволяют настраивать его внешний вид, взаимодействовать с контейнером и
использовать навигацию. Для перехода на другую страницу необходимо использовать
навигацию.
Класс Page имеет
следующие свойства:
Background – принимает кисть, которая устанавливает заливку для фона;
Content – принимает один элемент, который отображается на странице.
Обычно в роли такого элемента выступает контейнер макета (элемент Grid или
StackPanel);
Foreground,
FontFamile, FontSize –
определяет используемый по умолчанию внешний вид для текста внутри страницы.
Значение этих свойств наследуется элементами внутри страницы.
WindowWidth,
WindowHeight – определяет внешний вид окна, в которое упаковывается
страница (не действуют, если страница обслуживается во фрейме);
NavigationService – возвращает ссылку на объект NavigationService, которую можно
использовать для отправки пользователя на другую страницу программным путем;
KeepAlive – определяет, должен ли объект страницы оставаться
действующим после перехода пользователя на другую страницу;
ShowsNavigationUI – определяет, должны ли в обслуживающем данную страницу
хосте отображаться навигационные элементы управления;
Title – устанавливает имя, которое должно применяться для страницы
в хронологии навигации;
Window Title – устанавливает заголовок окна, который отображается в строке
заголовка.
Добавим в проект начальную страницу. Для этого в Обозревателе
решений щелкнем правой кнопкой мыши на проекте Wpf_FIO. В контекстном меню
выберем пункт Добавить (1 –
на Рисунок 8),
а в раскрывающемся меню пункт Страница
(2 на Рисунок 7).
Рисунок 7. Меню создания страницы
В окне Добавления нового элемента необходимо
выбрать шаблон «Страница (WPF)»
(1) и задать имя страницы PageMain (2 на Рисунок 8).
Рисунок 8. Окно Добавления нового элемента
В дизайнере проекта сгенерируется страница PageMain.xaml (Рисунок 9).
Рисунок 9. Дизайнер страницы PageMain.xaml
В сгенерированной странице в качестве контейнера верхнего
уровня используется Grid.
Заменим Grid на контейнер StackPanel.
Объект StackPanel имеет
свойство Background,
которое предоставляет кисть для рисования фоновой области элемента. Данное
свойство является сложным, т.е. должно задаваться в следующем виде:
<StackPanel.Background>
…
</StackPanel.Background>
Классы кистей наследуются от
класса System.Windows.Media.Brush и обеспечивают различные эффекты при заполнении фона,
переднего плана или границ элементов. Некоторые классы кистей приведены ниже:
LineaGradientBrush – рисует область, используя линейное градиентное заполнение,
представляющее собой плавный переход от одного цвета к другому;
RadialGradientBrush – рисует область, используя радиальное градиентное
заполнение, представляющее собой плавный переход от одного цвета к другому в
радиальном направлении от центральной точки;
ImageBrush – рисует область, используя графическое изображение, которое
может растягиваться, масштабироваться или многократно повторяться;
DrawingBrush – рисует область, используя объекты Drawing, которые могут быть
пользовательскими фигурами или битовыми картами;
VisualBrush – рисует область, используя объекты Visual.
Создадим градиентную заливку созданной страницы. Для
определения градиентной заливки необходимо создать объект
LinearGradientBrush.
Далее необходимо заполнить свойство LinearGradientBrush.GradientStops коллекцией объектов GradientStop. Каждый объект GradientStop имеет
свойства Offset и Color,
значение которых задаются в соответствии с синтаксисом
» свойство — атрибут «. Свойство Offset может
принимать значение от 0 до 1, определяя области
заполнения градиентом от одного цвета к другому.
Далее приведен фрагмент XAML-документа
для определения градиентной заливки страницы.
Добавим в страницу текстовую строку
«Система внутреннего учета инвестиционной компании».
Подключим созданную страницу к
фрейму. Для этого в разметке фрейма необходимо указать источник его заполнения Source, а также определим
свойства Foreground, BorderBrush и
Background.
Главная
страница приложения в дизайнере представлена на Рисунок 10.
Рисунок 10. Главная страница WPF-приложения в
дизайнере
Изменим свойство Title окна класса Window,
присвоив ему значение «Информационная система
ВУ«. Результат компиляции и выполнения WPF-приложения приведен на Рисунок 11.
Рисунок 11. Главная страница WPF-приложения
Контейнером верхнего уровня главной страницы приложения
является StackPanel.
Для данной панели свойству Background,
которое определяет кисть для рисования фоновой области, установлено сложное значение, определяющее градиентную заливку. С учетом того,
что в приложении предполагается использовать аналогичную градиентную кисть и
для других страниц, то целесообразным является сформировать значение
для данной кисти в виде ресурса, разместив его на уровне приложения. Для этого
найдите в Обозревателе решения файл приложения App.xaml и добавьте в него ресурс:
Сформированный ресурс
для градиентной кисти имеет ключ BackgroundWindowResource. Введение в XAML описание приложения ресурса требует провести изменение
свойства Background панели StackPanel,
использую расширения разметки и ссылку на статический ресурс
BackgroundWindowResource.
На странице WPF-приложения можно
размещать элементы пользовательского интерфейса (элементы
управления) для обеспечения взаимодействия пользователя с бизнес-логикой
системы.
3.
Навигация страничного приложения
Основная страница должна обеспечивать переход на другие
страницы, обеспечивающие интерфейс для отдельных функций и выход
из системы. Для перехода на другие страницы будем использовать гиперссылки.
Гиперссылки позволяют пользователю перемещаться с одной страницы на другую.
Элемент гиперссылки, соответствующий объекту класса Hyperlink, определяется следующей строкой:
<Hyperlink NavigateUri=»PageName.xaml»>Текст Гиперссылки</Hyperlink>
Класс Hyperlink имеет
свойство NavigateUri.
Данное свойство определяет на какую страницу будет переходить приложение при щелчке на соответствующей гиперссылке.
Например, NavigateUri=»Page2.xaml».
В WPF гиперссылки являются не отдельными, а внутристроковыми
потоковыми элементами, которые должны размещаться внутри другого поддерживающего
их элемента. Это можно сделать, например в элементе TextBlock, который для гиперссылки
является контейнером.
На первой странице создадим следующие гиперссылки: Сотрудники, Клиенты,
Договора, Ценные
бумаги, Сделки и Справка. XAML-описание гиперссылки
для страницы Сотрудники приведено ниже.
Остальные гиперссылки
добавьте самостоятельно.
Для реализации функциональности первого окна WPF-приложения
осталось добавить кнопку выхода.
Результат компиляции и выполнения
WPF-приложения приведен на Рисунок 12.
Рисунок 12. Начальная страница WPF-приложения с
гиперссылками
По условию учебного примера будем
постепенно добавлять функциональность приложения в части обработки данных по сотрудникам компании.
Создадим страницу с именем PageEmployee. В качестве основного контейнера будем использовать панель StackPanel. Определим для неё
градиентную заливку, аналогичную начальной странице приложения.
Страница PageEmployee должна
обеспечивать пользователю просмотр данных по сотрудникам, ввод
данных по новому сотруднику, редактирование, поиск и удаление данных. Доступ
пользователя к функциональности системы будем предоставлять через различные меню.
4.
Проектирование
интерфейса
В WPF можно создать основное
и контекстное меню.
Кроме того, можно создать панель
инструментов с кнопками, которые будут реализовывать функциональность,
аналогичную пунктам меню.
Основное меню создается с помощью класса
Menu, который
представляет Windows элементы управления меню, позволяющие иерархически организовать элементы,
связанные с командами и обработчиками событий. Меню формируют
из объектов MenuItem (имя пункта меню) и Separator (разделитель).
Класс MenuItem имеет свойство Header,
которое определяет текст элемента меню. Данный класс может хранить коллекцию объектов MenuItem, которая соответствует подпунктам
меню. Класс Separator отображает
горизонтальную линию, разделяющую пункты меню.
Добавим в StackPanel страницы PageEmployee XAML- описание меню,
которое на верхнем уровне будет содержать два пункта Действие и Отчет.
Пункт Действие включает
подпункты Отменить, Создать, Редактировать,
Сохранить, Найти и Удалить.
Между пунктами Отменить, Создать и пунктами Найти, Удалить
добавлены разделительные линии.
Запустим приложение
и выберем ссылку Сотрудники на странице PageEmployee. При выборе пункта
меню Действие появляется
выпадающий список и пунктами подменю (Рисунок 13).
Рисунок 13. Главное меню страницы PageEmployee
Панель инструментов представляет
специализированный контейнер для хранения коллекции
элементов, обычно кнопок. Расположим в панели инструментов кнопки,
функциональное назначение которых будет соответствовать подпунктам меню Действие, то
есть Отменить, Создать, Редактировать,
Сохранить, Найти и Удалить.
На лицевой стороне кнопок поместим графическое изображение соответствующего
действия. Для этого добавим в файл проекта папку Images и
в неё включим графические объекты, которые можно найти в стандартной библиотеке
графических объектов Visual Studio (в
файле VS2013 Image Library.zip,
его всегда можно бесплатно скачать с официального сайта Microsoft, для вас архив можно скачать по ссылке: VS2013 Image Library).
После добавления графических файлов в проект они будут
отображены в обозревателе решений (Рисунок 14).
Рисунок 14. Включение в проект папки Images с файлами рисунков
Теперь можно разработать XAML-описание
панели инструментов для страницы PageEmployee.
Для каждой кнопки зададим свойство Name – имя объекта в программе и свойство ToolTip с текстом
всплывающей подсказки при наведении указателя мыши на кнопку.
Свойство Margin определяет внешние отступы для
кнопки. Задание графического объекта для кнопки осуществляется определением для
объекта Image источника Source,
который должен соответствовать полному пути к графическому файлу.
В дизайнере Visual Studio страница
PageEmployee примет вид, приведенный на Рисунок 15.
Добавьте все необходимые кнопки на панель инструментов приложения.
Рисунок 15. Страниц PageEmployee с панелью инструментов в
дизайнере
После запуска приложения и выборе кнопки панели инструментов Добавить (Add) страница PageEmployee будет иметь вид, приведенный на Рисунок 16.
Рисунок 16. Страница PageEmployee с панелью инструментов
Следующим шагом проектирования интерфейсных элементов для
страницы PageEmployee является решение задачи формирования отображения данных по сотрудникам предприятия. Данная задача может быть решена
различными способами: с помощью элементов контроля ListBox, ListView, TextBox, TextBlock, ComboBox, DataGrid и других.
В учебном примере будем использовать элемент контроля DataGrid для
табличного отображения данных о сотрудниках. В качестве заголовка таблицы
применим текстовый блок «Список сотрудников«.
Класс DataGrid представляет
элемент управления, отображающий данные в настраиваемой сетке строк и столбцов.
По умолчанию DataGrid автоматически создает столбцы, на основе источника данных.
При этом генерируются следующие типы столбцов:
DataGridTextColumn – для отображения в ячейках столбцов текстового содержимого;
DataGridCheckBoxColomn – для отображения в ячейках столбцов логических данных;
DataGridComboBoxColomn – для отображения в ячейках столбцов данных, когда имеется
набор элементов для выбора;
DataGridHyperlinkColomn – для отображения в ячейках столбцов элементов Uri.
Если разработчика не устраивает автоматическая генерация
столбцов DataGrid можно её отключить. Для этого свойству AutoGenerateColumns необходимо
присвоить значение false. Далее можно создать собственный
набор столбцов (Columns),
используя существующие типы столбцов или создать новый тип столбца с помощью
шаблона DataGridTemplateColumn.
DataGrid поддерживает множество способов настройки отображения
данных. В Таблица 1
приведен список стандартных сценариев.
Таблица 1. Сценарии настройки отображения
данных
Сценарий |
Подход |
Переменные цвета фона |
Задайте для свойства AlternationIndex значение 2 или больше, а затем назначьте объект Brush свойствам |
Определение поведения при выборе ячейки и строки |
Установите свойства SelectionMode и SelectionUnit. |
Настройка внешнего вида заголовков, ячеек и строк |
Примените новый Style к свойствам ColumnHeaderStyle, |
Доступ к выбранным элементам |
Проверьте свойство SelectedCells, |
Настройка взаимодействия с пользователем |
Установите свойства CanUserAddRows, |
Отмена или изменение автоматически созданных столбцов |
Обработать событие AutoGeneratingColumn. |
Заморозка столбца |
Задайте для свойства FrozenColumnCount значение 1 и переместите столбец в крайнюю левую позицию, |
В качестве источника данных используются данные XML. |
Привяжите ItemsSource в DataGrid к запросу XPath, |
XAML-документ описания интерфейсных
элементов страницы PageEmployee
имеет следующий вид.
Для полей Фамилия, Имя,
Отчество, Телефон
и Электронная почта
используется тип столбца DataGridTextColumn.
Так как должность сотрудника задается в соответствии с данными из справочника базы данных, то есть предоставляется список,
из которого можно произвести выбор, для данного столбца используется тип DataGridComboBoxColumn. Для
столбца Дата рождения используется
специфичный шаблон, то есть тип DataGridTemplateColumn, который будет
описан позднее.
С учетом добавленных интерфейсных элементов страница PageEmployee в
дизайнере примет вид, приведенный на Рисунок 17.
Рисунок 17. Страница PageEmployee с элементом DataGrid в дизайнере
После запуска приложения страница PageEmployee будет
иметь вид, приведенный на Рисунок 18.
Рисунок 18. Страница PageEmployee с элементом DataGrid
На данном этапе проектирования приложения на странице PageEmployee размещены
все необходимые элементы контроля.
5.
Разработка бизнес-логики
Для реализации функциональности приложения в части обработки
информации о сотрудниках предприятия необходимо для страницы PageEmployee установить
механизм запуска задач (Отменить, Создать, Редактировать,
Сохранить, Найти и Удалить)
при выборе соответствующих пунктов меню и нажатии на
кнопки панели инструментов. Технология WPF предлагает модель команд для выполнения такой привязки.
Модель команд обеспечивает
делегирование событий определенным командам и управление
доступностью элементов управления в зависимости от состояния соответствующей
команды. В WPF команда
представляет собой задачу приложения и механизм слежения за
тем, когда она может быть выполнена. В то же время сама команда
не содержит конкретного кода выполнения задачи. Одна и та же команда может быть привязана к одному или нескольким
интерфейсным элементам приложения. Инициируют
команду источники, которые могут быть различными элементами управления,
например пункты меню MenuItem или
кнопки – Button. Целевым объектом команды является элемент, для
которого предназначена эта команда.
Классы, реализующие команды должны поддерживать интерфейс ICommand.
В этом интерфейсе определены два метода Execute, CanExecute и событие CanExecuteChanged.
В WPF имеется библиотека
базовых команд. Команды доступны через статические свойства следующих
статических классов:
ApplicationCommands;
NavigationCommands;
EditingCommands;
MediaCommands.
Для создания пользовательских команд целесообразно
использовать классы RoutedCommand,
который имеет реализацию интерфейса ICommand.
В разрабатываемом приложении для функций Отменить, Создать,
Сохранить и Найти будем использовать стандартные команды из библиотеки WPF –
статический класс ApplicationCommands, а для функций Редактировать и Удалить
спроектируем пользовательские команды.
Для разработки пользовательских команд добавим в проект
папку Commands и в ней создадим класс DataCommands.
В классе DataCommands объявлены
два свойства Delete и Edit типа RoutedCommand.
Класс RoutedCommand определяет команду, реализующую ICommand. В конструкторе данного класса
определяется объект inputs типа InputGestureCollection. Класс InputGestureCollection представляет упорядоченную коллекцию объектов InputGesture, которые позволяют
с помощью класса KeyGesture задать комбинацию клавиш для вызова команды.
Для использования страницей PageEmployee пользовательских
команд в XAML-документе необходимо добавить пространство имен, где расположен класс
DataCommands. Данному
пространству имен присвоим ссылку command.
xmlns:command=»clr-namespace:Wpf_Erina.Commands»
Теперь для страницы PageEmployee сформируем
коллекцию объектов CommandBinding,
которая осуществляет привязку команд для данного элемента и объявляет связь между командой, ее событиями и обработчиками.Для функций Отменить, Создать, Сохранить
и Найти, основанных на стандартных командах
из библиотеки WPF, привязка выглядит следующим образом:
Для класса CommandBinding свойство
Command определяет ссылку на соответствующую команду, а свойства Executed и
CanExecute задают обработчики событий при выполнении команды.
Добавьте привязки для
следующих команд: Отменить –
Undo,
Создать –
New,
Сохранить –
Save,
Найти –
Find.
Для функций Редактировать и Удалить, использующих пользовательские команды,
необходимо сделать указать, что команда берется из пространства имен Wpf_Erina.Commands:
Добавьте привязки для команд Редактировать – Edit и Удалить – Delete.
Итак, на странице приложения используются следующие команды: Отменить, Создать,
Редактировать, Поиск, Сохранить
и Удалить. Команды могут быть доступны
или недоступны пользователю при работе приложения. Это проверяет метод CanExecute при
генерации события CanExecuteChanged,
которое вызывается при изменении состояния команды. Доступность команд
определяется состоянием, в котором находится приложение.
В тоже время выполнение какой-либо команды переводит, как правило, приложение в какое-либо другое состояние. Для
проектируемого приложения можно определить следующие состояния:
·
первоначальная загрузка страницы (1);
·
просмотр данных по всем сотрудникам (2);
·
редактирование данных по отдельному сотруднику
(3);
·
создание новой записи по сотруднику в базе
данных (4).
На Рисунок 19
приведена диаграмма состояний приложения, на которой
кружками обозначены состояния, а дуги соответствуют переходам при выполнении
определенной команды.
Рисунок 19. Диаграмма состояний приложения
На основе диаграммы состояний построим
таблицу доступности команд в различных состояниях (Таблица 2).
Таблица 2. Доступность команд в различных
состояниях приложения
Состояние |
Доступность команд |
|||||
Сохранить Save |
Отменить
Undo
|
Создать
New
|
Поиск
Find
|
Редактировать
Edit
|
Удалить
Delete
|
|
1 |
false |
false |
true |
true |
true |
true |
2 |
false |
false |
true |
true |
true |
true |
3 |
true |
true |
false |
false |
false |
false |
4 |
true |
true |
false |
false |
false |
false |
Из Таблица 2
видно, что в приложении режим доступности команд в состояниях 1 и 2
противоположно режиму доступности команд в состояниях 3 и 4. Фактически для
приложения имеются два режима (один объединяет состояния 1 «Первоначальная
загрузка» и 2 «Просмотр данных по всем сотрудникам», а второй – состояния 3 «Редактирование
данных по одному сотруднику» и 4 «Создание новой записи по сотруднику»),
управлять которыми можно с помощью логической
переменной.
В код программы класса PageEmployee введем
логическое поле isDirty для управления доступностью
команд.
private bool isDirty = true;
В код класса добавим обработчики команд,
определяющие бизнес-логику приложения (реализация методов Executed). На данном этапе проектирования
системы обработчики будут содержать только вывод сообщений
о вызове команды и изменение поля isDirty.
Код обработчика команды Отменить приведен
ниже.
Добавьте ВСЕ обработчики команд Executed
В дальнейшем в обработчики добавим код для обеспечения
требуемой функциональности.
В коде класса остается добавить обработчики, которые
управляют доступностью команд (реализация метода CanExecute). Так как при анализе Таблица 2
было выявлено, что для приложения различимо только два состояния доступности
команд, то и обработчиков тоже достаточно иметь в программе два.
Исправьте в XAML-документе в
привязке команд к обработчикам событий, у всех остальных команд привязку к одному
из этих обработчиков. При этом учтите, что команды первой группы устанавливают
значение поля isDirty в Истину, а команды второй группы устанавливают
ее в Ложь.
Теперь необходимо модифицировать XAML-документ в части задания свойства Command при
описании пунктов меню и панели инструментов для привязки
команд.
При описании меню (Menu) XAML-документ
модифицирован следующим образом.
Соответствующие изменения XAML-документа необходимо провести и для панели
инструментов ToolBar.
Внесите изменения для всех
пунктов меню и всех кнопок панели инструментов.
При выполнении приложения различные состояния доступности
пунктов меню приведены на Рисунок 20
и Рисунок 21.
Рисунок 20. Состояние доступности пунктов меню после
загрузки приложения
Рисунок 21. Состояние доступности пунктов меню
после редактирования данных
При выборе какого-либо пункта меню,
например пункта Создать, система выдает
сообщение (Рисунок
22).
Рисунок 22. Выбор пункта меню Создать
Следующим этапом разработки приложения является создание
источника данных, который обеспечит взаимодействие приложения с базой данных.
Ключевые термины
Приложение WPF, пространство
имен, атрибут, частичный класс,
простое свойство, сложное свойство, фрейм, гиперссылка, меню, панель инструментов, команда,
привязка команд.
MainWindow,
xmlns, partial, InitializeComponent, NavigationWindow, Frame, FrameworkElement,
Page, Hyperlink, NavigateUri, Menu,
MenuItem, DataGrid, DataGridTextColomn,
DataGridCheckBoxColomn, DataGridComboBoxColomn, DataGridHyperlinkColomn,
DataGridTemplateColumn, ICommand, Execute, CanExecute, CanExecuteChanged,
CommandBinding.
Краткие итоги
В данной работе были рассмотрены вопросы разработки
страничного WPF-приложения, организации перехода по страницам,
создания системы меню, панели команд, табличного
представления информации для просмотра и редактирования данных, системы
универсальных команд многократного использования.
Ресурсы для углубленного изучения
Application Development
// http://msdn.microsoft.com/ru—ru/library/ms754032.aspx.
Система макета // http://msdn.microsoft.com/ru-ru/library/ms745058.aspx.
Библиотека классов // http://msdn.microsoft.com/ru-ru/library/ms753307.aspx.
[ 4
] ,
стр. 82 – 174, 288 – 362.
[ 6
] ,
стр. 1171 — 1212
[ 8
] ,
стр. 297 – 351,565 – 625.
[ 9
] ,
стр. 1048 – 1070.
Вопросы для самопроверки
1.
Какой дескриптор верхнего уровня используется в
WPF-проектах?
2.
Какое назначение метода InitializeComponent() в
коде класса?
3.
Сколько можно вложить элементов в класс Page?
4.
Поясните назначение свойства Content класса
Page.
5.
В каких контейнерах можно размещать страницы
WPF?
6.
Какие элементы контроля используются для
перехода между страницами приложения?
7.
Из каких объектов можно сформировать меню
приложения?
8.
Какие типы столбцов автоматически генерируются
для элемента управления DataGrid?
9.
Поясните назначение модели команд WPF.
10. Какие
в WPF имеется библиотеки базовых команд?
11. Как
можно управлять доступностью команд в приложении WPF?