Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Разработка графического пользовательского интерфейса в соответствии с паттерном Model-View-Viewmodel на платформе Windows Presentation Foundation. Осн

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
1 Мб
Скачать
☆

// начало файла ViewCommands.cs using System;

using System.Windows;

using System.Windows.Controls; using System.Windows.Input; using Microsoft.Win32;

namespace ImageViewer

{

class ViewCommands

{

//-------------------------------------------

public static void ExecuteLoadImage

(

object target, ExecutedRoutedEventArgs e

)

{

OpenFileDialog ofd =

new OpenFileDialog();

ofd.Filter =

"Image files|*.jpg;*.jpeg;*.png;*.gif;*.bmp";

Nullable<bool> result = ofd.ShowDialog();

if(result.HasValue)

{

if(result.Value == true)

{

ViewModel vm =

e.Parameter as ViewModel;

vm.PicturePath = ofd.FileName;

vm.Picture =

vm.controller.LoadImage

(

vm.PicturePath

);

vm.PictureWidth =

vm.controller.PixelWidth;

vm.PictureHeight =

51

vm.controller.PixelHeight;

}

}

}

//-------------------------------------------

public static void ExecuteInvertImage

(

object target, ExecutedRoutedEventArgs e

)

{

ViewModel vm = e.Parameter as ViewModel;

vm.Picture = vm.controller.InvertImage();

}

//-------------------------------------------

public static void ExecuteClickImage

(

object target, ExecutedRoutedEventArgs e

)

{

FrameworkElement fe =

target as FrameworkElement;

while(true)

{

FrameworkElement node =

fe.Parent as FrameworkElement;

if (node == null)

{

break;

}

if (node.GetType() == typeof(ScrollViewer))

{

ViewModel vm =

e.Parameter as ViewModel;

new ViewEvents().

HandlePictureDragging

(

fe,

52

node as ScrollViewer );

break;

}

}

}

//-------------------------------------------

}

}

// конец файла ViewCommands.cs

Врассматриваемом примере класс ViewCommands — статический. С одной стороны, у него нет необходимости в хранении данных экземпляра (у него вообще нет своих данных). С другой стороны, этот класс не вполне самостоятельный и фактически активно пользуется данными объекта ViewModel, ссылка на который присутствует в аргументах всех команд.

Алгоритмические действия по обработке команд здесь сводятся к перенаправлению контроллеру сообщений из GUI. Модификация значений таких связываемых свойств объекта ViewModel, как Picture, автоматически отражается на визуальных элементах GUI.

Вметоде ExecuteClickImage обрабатывается начало перетаскивания мышью видимой области изображения. Этот метод вызывается как реакция на команду ClickImage, которая может быть инициирована только одним способом — нажатием левой клавиши мыши на изображении внутри компонента Image. Связывание команды ClickImage приведено в декларативном коде на XAML. Если в дереве визуальных элементов выше от узла Image обнаружится компонент ScrollViewer, происходит создание экземпляра ViewEvents и вызов его метода HandlePictureDragging. Если компонента ScrollViewer в дереве нет, команда игнорируется.

// начало файла ViewEvents.cs using System;

using System.Windows;

53

using System.Windows.Input; using System.Windows.Controls;

namespace ImageViewer

{

class ViewEvents

{

//-------------------------------------------

private ScrollViewer scroller; private bool dragging = false; private Point previousPoint;

//-------------------------------------------

public void HandlePictureDragging

(

FrameworkElement

targetElement, ScrollViewer argScroller

)

{

if(Mouse.LeftButton == MouseButtonState.Pressed)

{

scroller = argScroller;

targetElement.MouseLeftButtonUp += OnMouseLeftButtonUp;

targetElement.MouseMove += OnMouseMove;

previousPoint = Mouse.GetPosition(scroller);

Mouse.Capture(targetElement);

dragging = true;

}

}

//-------------------------------------------

private void OnMouseMove

(

object sender, MouseEventArgs e

)

{

54

if(dragging &&

(e.LeftButton == MouseButtonState.Pressed))

{

Point nowPoint =

e.GetPosition(scroller);

Vector shift =

nowPoint - previousPoint;

previousPoint = nowPoint;

Point currentOffset = new Point

(

scroller.ContentHorizontalOffset,

scroller.ContentVerticalOffset

);

scroller.ScrollToHorizontalOffset

(

currentOffset.X - shift.X );

scroller.ScrollToVerticalOffset

(

currentOffset.Y - shift.Y );

}

e.Handled = true;

}

//-------------------------------------------

private void OnMouseLeftButtonUp

(

object sender, MouseButtonEventArgs e

)

{

dragging = false;

FrameworkElement fe =

sender as FrameworkElement;

fe.MouseLeftButtonUp -= OnMouseLeftButtonUp;

55

fe.MouseMove -= OnMouseMove;

Mouse.Capture(null);

e.Handled = true;

}

//-------------------------------------------

}

}

// конец файла ViewEvents.cs

Экземпляр класса ViewEvents существует только во время панорамирования изображения мышью. В момент отжатия левой клавиши мыши обработчики событий снимаются с визуального элемента, ссылок на объект ViewEvents не остается и он утилизируется сборщиком мусора.

Центральную роль в обслуживании панорамирования мышью иг-

рают вызовы методов ScrollToHorizontalOffset и ScrollToVerticalOffset

класса ScrollViewer. Это происходит при реакции на движение мыши (OnMouseMove). Вычисляется относительное смещение курсора с момента предыдущего события MouseMove и на соответствующую величину параллельно переносится видимая область в контейнере ScrollViewer. Таким образом, изображению невозможно сместиться от курсора мыши — оно будто «приклеивается» к движущемуся курсору.

<!-- начало файла MainWindow.xaml --> <Window

x:Class="ImageViewer.MainWindow"

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

presentation"

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

l" xmlns:custom="clr-namespace:ImageViewer" Title="Image View 1.0"

>

56

<Window.Resources> <custom:ViewModel x:Key="view"/>

<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Width" Value="150"/>

<Setter Property="Height" Value="150"/> <Setter Property="Margin" Value="5, 5, 5, 0"/> </Style>

</Window.Resources>

<Window.CommandBindings>

<CommandBinding

Command=

"{x:Static

custom:ViewModel.LoadImage}"

Executed=

"{x:Static

custom:ViewModel.ExecutedLoadImageHandler}"

/>

<CommandBinding

Command=

"{x:Static

custom:ViewModel.InvertImage}"

Executed=

"{x:Static

custom:ViewModel.ExecutedInvertImageHandler}"

/>

</Window.CommandBindings>

<Window.InputBindings>

<KeyBinding

Key="O"

Modifiers="Control"

Command="{x:Static

custom:ViewModel.LoadImage}" CommandParameter="{StaticResource view}" />

<KeyBinding

Key="I"

Modifiers="Control"

Command="{x:Static

custom:ViewModel.InvertImage}"

CommandParameter= "{StaticResource view}"

/>

</Window.InputBindings>

57

<DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Left" Orientation="Vertical"

>

<Button

Style="{StaticResource ButtonStyle}" Command="{x:Static

custom:ViewModel.LoadImage}"

CommandParameter=

"{StaticResource view}"

>

Open image (Ctrl+O) </Button>

<Button

Style="{StaticResource ButtonStyle}" Command="{x:Static

custom:ViewModel.InvertImage}"

CommandParameter=

"{StaticResource view}"

>

Invert image (Ctrl+I) </Button> </StackPanel> <TextBlock DockPanel.Dock="Bottom"

Text="{Binding PicturePath, Source={StaticResource view}}"

/>

<ScrollViewer

Background="LightGray"

Padding="5"

HorizontalScrollBarVisibility="Auto"

VerticalScrollBarVisibility="Auto">

<Image

DataContext="{StaticResource view}" Source="{Binding Picture}" Width="{Binding PictureWidth}"

>

<Image.CommandBindings>

<CommandBinding

Command="{x:Static

custom:ViewModel.ClickImage}"

Executed="{x:Static

58

custom:ViewModel.ExecutedClickImageHandler}"

/>

</Image.CommandBindings>

<Image.InputBindings>

<MouseBinding

Gesture="LeftClick"

Command="{x:Static

custom:ViewModel.ClickImage}"

CommandParameter=

"{StaticResource view}"

/>

</Image.InputBindings>

</Image>

</ScrollViewer>

</DockPanel>

</Window>

<!-- конец файла MainWindow.xaml -->

В этом декларативном описании формируется дерево визуальных элементов рабочей области главного окна приложения. Экземпляр CLRкласса ViewModel помещен в секции ресурсов окна. Определено связывание команд (CommandBinding) с обработчиками. Определено также связывание жестов устройств ввода с командами (KeyBinding, MouseBinding). Команда LoadImage вызывается как нажатием комбинации клавиш Ctrl+O, так и кнопкой с надписью «Open image». Команда InvertImage вызывается комбинацией клавиш Ctrl+I или кнопкой «Invert image». Команда ClickImage инициируется нажатием левой клавиши мыши на визуальном элементе Image.

59

Библиографический список

1. Мандел, Т. Разработка пользовательского интерфейса : пер. с англ. /

Т.Мандел - Москва: ДМК Пресс, 2001. - 416 с.

2. Макдональд, М. WPF4: Windows Presentation Foundation в .NET 4.0 с

примерами на C# 2010 для профессионалов. : пер. с англ. / М. Макдональд -

Москва: Вильямс, 2011. - 1024 с.

3. Макдональд, М. WPF: Windows Presentation Foundation в .NET 4.5 с

примерами на C# 5.0 для профессионалов. : пер. с англ. / М. Макдональд -

Москва: Вильямс, 2013. - 1024 с.

60

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]