| исключение в лабораторной работе № 3 |
Графика в WPF
-
Командой Project/Add Reference добавьте к проекту ссылку на библиотеку System.Windows.Forms.dll, в которой
находится перечисление Keys кодов клавиш
-
Запустите проект FullScreen и
испытайте построенную нами имитацию полноэкранного режима
Оконный и полноэкранный (уменьшенный масштаб) режимы будут выглядеть так
Главное меню мы создали для примера, чтобы показать, что его можно отключать в полноэкранном режиме. Переключение режимов выполняется вызовом контекстного меню по щелчку правой кнопки мыши на окне приложения. В полноэкранном режиме отключаются нежелательные для нас системные клавиши, которые могли бы привести к сбою режима:
- CTRL + ESC: открытие меню Пуск.
- Клавиша WIN: открытие меню Пуск.
- ALT + ESC: показать панель задач и переключать развернутые окна.
- ALT + TAB: переключение между программами.
В оконном режиме функциональность системных клавиш восстанавливается.
Для полного сходства можно было бы отключить мышь, но тогда все управление окном нужно будет возложить на клавиатуру. В нашем приложении мы для закрытия окна использовали клавишу Esc. Закрыть окно можно и системной комбинацией Alt+F4, которую мы не отключали. Осталась активной комбинация Alt+Space, вызывающая системное меню приложения.
Мы использовали в классе HookSystemKeys перечисление System.Windows.Forms.Keys библиотечной сборки System.Windows.Forms, а в обработчике Window_KeyDown - перечисление System.Windows.Input.Key библиотечной сборки WindowsBase.dll. Это разные перечисления и их нельзя путать.
-
Попробуйте разобраться
с кодом
Упражнение 3. Применение объекта ImageDrawing
Объект ImageDrawing принимает графические данные в виде битовой карты (точечного рисунка). Для создания изображения необходимо создать экземпляр ImageDrawing и установить значения его свойств ImageDrawing.ImageSource и ImageDrawing.Rect. Свойство ImageDrawing.ImageSource задает изображение для рисования, а свойство ImageDrawing.Rect задает положение и размер каждого изображения.
Если нужно отобразить один рисунок, то его сразу можно присоединить к объекту отображения Image, как мы это делали в предыдущем упражнении. Если же требуется нарисовать несколько рисунков сразу, то необходимо организовать конвейер формирования рисунков. Вначале создаются отдельные слои с помощью ImageDrawing, затем они передаются в накопитель DrawingGroup, где располагаются в Z -последовательности в порядке их добавления. В таком порядке каждый новый слой будет перекрывать все предыдущие и располагаться ближе к пользователю. Затем этот слоеный объект передается в рисовальщик DrawingImage, который и присоединяется, в конечном итоге, к элементу отображения Image.
Объект DrawingGroup как составной объект рисования, может принимать не только точечные рисунки. В первом упражнении мы использовали его для накопления векторных рисунков геометрии, порожденных объектом GeometryDrawing. Он также способен принимать текстовые данные от GlyphRunDrawing, или медийные данные звука и видео от объекта VideoDrawing. Объект DrawingGroup является единственным типом базового объекта Drawing, который позволяет определять свою собственную область отсечения. Но об этом чуть позже, а сейчас приступим к рассмотрению объекта ImageDrawing.
Класс ImageDrawing легко спутать с важным классом DrawingImage, названия которых так похожи. Но это нас не должно путать, если мы представим изготовление готового рисунка как последовательность операций на конвейере. Это будет выглядеть примерно так:
-
Добавьте к решению
проект типа WPF Application с именем WpfApp3 и
назначьте его стартовым -
Добавьте к проекту
командой Project/New Folder папку с именем Images
-
В панели Solution
Explorer вызовите контекстное меню для папки Images и скопируйте в нее командой Add/Existing Item из прилагаемого каталога Source пять файлов с рисунками (не забудьте изменить
фильтр диалогового окна Add Existing Item на All Files ):- market 031.jpg
- market 032.jpg
- market 034.jpg
- market 039.jpg
- market 040.jpg
-
В панели Solution
Explorer выделите все пять рисунков одновременно и в панели Properties установите
для них свойства- Build Action=Content
- Copy to Output Directory=Copy if newer
В этом упражнении мы рассмотрим два способа использования объекта ImageDrawing - с помощью разметки на XAML и с помощью кода C#. Оба способа работают совершенно одинаково и для того, чтобы это подчеркнуть, мы с помощью них реализуем одну и ту же задачу. Попутно рассмотрим решение некоторых мелких вопросов, таких, как предотвращение повторного запуска созданного окна приложения, назначение главного окна и формирование всплывающей подсказки.
Вначале создадим главное окно приложения Window1, в котором примененим объект ImageDrawing в кодовой части Window1.xaml.cs. Затем построим дочернее окно Window2, в котором используем объект ImageDrawing в дискрипторной части Window2.xaml.
-
Заполните файл разметки Window1.xaml следующим дескрипторным кодом
<Window x:Class="WpfApp3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Главное окно Window1: Работа объекта ImageDrawing через процедурный код"
Loaded="Window_Loaded"
MouseDoubleClick="Show_Window2"
SizeToContent="WidthAndHeight"
ResizeMode="NoResize">
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Создать дочернее окно" Click="Create_Window2" />
</ContextMenu>
</Window.ContextMenu>
</Window>Эта разметка настраивает окно и создает контекстное меню с одним пунктом. Вызов дочернего окна, которое будет иллюстрировать разметочный способ применения объекта ImageDrawing, предусмотрим в обработчиках событий MouseDoubleClick окна и Click контекстного меню. Такое дублирование одной и той же задачи создания дочернего окна выбрано потому, чтобы испытать разные способы предотвращения повторного запуска уже существующего окна.
Событие Loaded срабатывает после загрузки окна в оперативную память, поэтому в его обработчик удобно поместить код создания объектов содержимого окна. Атрибуты SizeToContent и ResizeMode дескриптора <Window> делают окно подстраиваемым под содержимое (при первом появлении) и неизменяемое в размерах пользователем, соответственно. Контекстное меню прикрепляется к объекту окна и будет вызываться в любой его точке, кроме заголовка.
-
Щелкните правой кнопкой
мыши на каждом из событий Loaded, MouseDoubleClick, Click и выполните команду Navigate to Event Handler,
чтобы создать в кодовой части обработчики с уже заготовленными именами -
В файле Window1.xaml.cs заполните обработчик события Loaded следующим кодом
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Размеры всех рисунков одинаковы
const int WIDTH = 348, HEIGHT = 232;
// Создаем накопитель рисунков DrawingGroup
DrawingGroup drawingGroup = new DrawingGroup();
// Левый верхний
ImageDrawing pict1 = new ImageDrawing();
pict1.Rect = new Rect(0, 0, WIDTH, HEIGHT);
pict1.ImageSource = new BitmapImage(
new Uri(@"Images\market 040.jpg", UriKind.Relative));
drawingGroup.Children.Add(pict1);
// Правый верхний
ImageDrawing pict2 = new ImageDrawing();
pict2.Rect = new Rect(350, 0, WIDTH, HEIGHT);
pict2.ImageSource = new BitmapImage(
new Uri(@"Images\market 039.jpg", UriKind.Relative));
drawingGroup.Children.Add(pict2);
// Левый нижний
ImageDrawing pict3 = new ImageDrawing();
pict3.Rect = new Rect(0, 234, WIDTH, HEIGHT);
pict3.ImageSource = new BitmapImage(
new Uri(@"Images\market 034.jpg", UriKind.Relative));
drawingGroup.Children.Add(pict3);
// Правый нижний
ImageDrawing pict4 = new ImageDrawing();
pict4.Rect = new Rect(350, 234, WIDTH, HEIGHT);
pict4.ImageSource = new BitmapImage(
new Uri(@"Images\market 032.jpg", UriKind.Relative));
drawingGroup.Children.Add(pict4);
// Передать рисовальщику
DrawingImage drawingImageSource = new DrawingImage(drawingGroup);
// Заморозить DrawingImage для лучшей производительности
drawingImageSource.Freeze();
// Передать элементу отображения
Image image = new Image();
image.Stretch = Stretch.None;
image.Source = drawingImageSource;
// Контейнер Border для присоединения к содержимому окна
Border border = new Border();
border.Background = Brushes.White;
border.BorderBrush = Brushes.White;
border.BorderThickness = new Thickness(2); // Толщина рамки
border.Margin = new Thickness(10); // Внешний отступ-поле
border.Child = image; // Отдать родителю
this.Background = Brushes.Blue;
this.Content = border;
}-
Дополните конструктор
окна Window1 следующим кодом
public Window1()
{
// Инициализация разметочной части
InitializeComponent();
// Корректировка заголовка окна
this.Title += "=\"Так голодают буржуины!\"";
// Всплывающая подсказка
this.ToolTip = "Вызывайте дочернее окно\n"
+ "двойным щелчком мыши\n"
+ "или контекстным меню...";
}Здесь применено экранирование двойных кавычек в строковой константе. В определении всплывающей подсказки использован управляющий символ новой строки.


