Хранение изображений

Оценить
(0 голоса)

Теперь, когда элементы пользовательского интерфейса находятся на своих местах, мы мо­жем перейти к вопросам привязки данных (к шлифовке пользовательского интерфейса мы вернемся чуть позже). Первая задача — сохранить файлы в некоей коллекции. Оказывается, в System. Windows .Media есть класс BitmapSource, который подходит для наших целей. В качестве коллекции подойдет объект List<BitmapSource>, но нам нужен способ запол­нения списка. Давайте создадим класс-оболочку, который загружает список и предоставляет его как свойство. Добавим в проект новый класс при помощи следующего кода:

public class DirectorylmageList {

private string _path;

private List<BitmapSource> images = new List<BitmapSource>();

public DirectoryImageList(string path)

{

_jpath = path;

Loadlmages();

}

public List<BitmapSource> Images

{

get { return _images; }

\

set { _images = value; }

}

public string Path

{

get { return _path; } set

{

_path = value;

Loadlmages();

}

}

private void Loadlmages()

{

_images.Clear();

Bitmap Image img;

foreach (string file in Directory.GetFiles(_path))

/

{

try

{

img = new BitmapImage(new Uri(file));

_images.Add(img);

}

catch

{

// empty catch; ignore any files that won't load as // an image...

}

i

Метод Loadlmages в предшествующем коде— это то место, где сосредоточена большая часть самой важной программной логики; он пересчитывает файлы внутри заданного ката­лога и пытается загрузить их в объект Bitmapimage. Если это получается, то мы знаем, что это файл изображения. Если не получается, то мы просто игнорируем исключительное со­стояние и продолжаем дальше.

В нашем классе windowl нам нужно создать несколько закрытых (private) полей для экзем­пляра этого нового класса, а также для текущего выбранного пути. Именно это может изме­нить пользователь при помощи диалога, запускаемого через пункт меню Folder | Open.

Вот эти поля:

private DirectoryImageList _imgList; private string _path =

Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

Обратите внимание, что в качестве пути по умолчанию мы приняли каталог Pictures. Для за­грузки объекта списка мы напишем метод ResetList в нашем классе Windows 1 (в файле вы­деленного кода _imgList объявлен как наш локальный экземпляр DirectorylmageList):

private void ResetList()

Рис. 16.23. Начальная привязка

Вспоминая наше более раннее обсуждение привязки данных, мы добавим несколько строк кода в конструктор Windowl: начальный вызов ResetList, а также вызов для присваивания контекста данных свойству Images экземпляра DirectorylmageList.

public Windowl()

{

InitializeComponent();

Хранение изображений

ResetList();

this.DataContext = _imgList.Images;

}

Если мы теперь запустим это приложение, то увидим знакомую картину (рис. 16.23): при­вязка данных работает, но не совсем в том формате, который нам нужен для представления.

Привязка к изображениям

Поскольку наш предыдущий фокус с перекрытием Tostring не дает нам нужного пред­ставления данных (потому что изображение — это не строка), то нам надо применить шаб­лоны данных. Класс DataTemplate используется для того, чтобы указать элементу управ­ления, как именно вы хотите отображать его данные. При помощи шаблона данных внутри дерева элементов вы имеете полную свободу в представлении привязанных данных.

В нашем приложении мы ищем изображения в ListBox. Это очень легко. Создайте в XAML элемент Windowl.Resources и создайте шаблон DataTemplate, который настраивает нужную нам визуализацию:

<Window.Resources>

<DataTemplate х:Кеу="ImageDataTemplate">

<Image Source="{Binding UriSource.LocalPath}" Width="125" Height="125" /> </DataTemplate>

</Window.Resources>

Затем присвойте ListBox шаблрн DataTemplate:   '

CListBox Grid.Row="l" Name=MlistBoxlM ItemsSource="{Binding}"

ItemTemplate="{StaticResource ImageDataTemplate}"/>

В нашем шаблоне данных элемент Image ждет указания URI для каждого изображения. По­этому мы используем UriSource. LocalPath объекта BitmapSource.

Щелчок по контрольному изображению в списке должен привести к показу выбранного изображения в центральном элементе управления Image. Создав обработчик события SelectionChanged и подключив его к ListBox, мы можем соответствующим образом об­новлять свойство Image. Source.

Событие объявляется в элементе ListBox вполне ожидаемым образом:

CListBox SelectionChanged=HlistBoxl_SelectionChanged" Grid.Row=f,l" Name="listBoxl" ItemsSource="{Binding}"

ItemTemplate="{StaticResource ImageDataTemplate}"/>

А для обработчика события мы приведем тип Selectedltem из ListBox к его родному пред­ставлению BitmapSource и присвоим его нашему элементу управления:

private void listBoxl_SelectionChanged(object sender,

SelectionChangedEventArgs e)

{

imagel.Source - (BitmapSource)((sender as ListBox).Selectedltem);

}

Обработчики событий кнопки и эффекты изображения

После того как изображение успешно загружено в список и показано в центральном элемен­те управления Image, мы можем заняться нашими четырьмя эффектами (опциями редакти­рования):

□    черно-белый фильтр;

□    размытость;

□    вращение;

□    переворот.

Поскольку эти четыре функции управляются четырьмя кнопками, то нам нужно будет доба­вить соответствующие изображения кнопок и события; мы не будем описывать здесь стили­зацию кнопок, поскольку для нее необходимы внешние графические ресурсы, но вы можете взглянуть на их окончательный вид на моментальном снимке экрана в конце данной главы (или скачать исходный код с Web-сайта этой книги).

Теперь — код для событий. Во-первых, XAML-объявления событий каждой кнопки:

<Button Click="buttonBandW_Click" Margin="20,0,0,0" Height="23" Name="buttonBandW" Width="30">Button</Button>

<Button Click="buttonBlur_Click" Margin="20,0,0,0" Height="23" Name="buttonBlur" Width="30">Button</Button>

'<Button Click="buttonRotate_Click" Margin="20,0,0,0" Height="23" Name="buttonRotate" Width="30">Button</Button>

<Button Click="buttonFlip_Click" Margin="20,0,20,0" Height="23" Name="buttonFlip" Width="30">Button</Button>

Обратите внимание, что по мере того как вы вводите эти события щелчков в панели XAML, редактор XAML выдает вам подсказки IntelliSense, которые не только дописывают наши объявления Click, но и создают соответствующие обработчики события в нашем классе выделенного кода (рис. 16.24)! Описание: image436

Рис. 16.24. Технология IntelliSense в действии внутри редактора XAML

Для манипулирования изображением мы используем преобразование: манипуляцию дву­мерной поверхностью для вращения, перекашивания и прочих изменений внешнего вида поверхности.

Мы можем выполнить нашу функцию вращения непосредственно при помощи RotateTransform следующим образом:

private void buttonRotate_Click(object sender, RoutedEventArgs e)

{

CachedBitmap cache = new CachedBitmap((BitmapSource)imagel.Source,

BitmapCreateOptions.None, BitmapCacheOption.OnLoad); imagel.Source = new TransformedBitmap(cache, new RotateTransform(90));

}

Наша функция переворота так же просто реализуется при помощи преобразования ScaleTransform:

private void buttonFlip_Click(object sender, RoutedEventArgs e)

{

CachedBitmap cache = new CachedBitmap((BitmapSource)imagel.Source,

BitmapCreateOptions.None, BitmapCacheOption.OnLoad); ScaleTransform scale = new ScaleTransform(-1,-1,imagel.Source.Width/2,

imagel.Source.Height / 2); imagel.Source = new TransformedBitmap(cache, scale);

)

Размывание изображения достигается при помощи другого механизма, известного как рас­тровый эффект. При помощи создания нового экземпляра BlurBitmapEffeet и присваива­ния его нашему элементу управления изображением WPF применит соответствующий алго­ритм к растровому изображению для размывания картинки:

imagel.BitmapEffeet = new BlurBitmapEffeet();

Выбор пути в обычном диалоговом окне

Последнее, что нам надо сделать— это дать пользователю возможность изменить путь к файлам картинок. Сама WPF не имеет для этого никаких встроенных классов, но простран­ство имен System, windows. Forms обладает как раз тем, что нам нужно,— классом FolderBrowse г Dialog. Он запускается из обработчика нашего события щелчка

Folde rOpenMenuItem:

private void FolderOpenMenuItem_Click(object sender, RoutedEventArgs e)

{

SetPath();

}

private void SetPathO {

FolderBrowserDialog dig = new FolderBrowserDialog();

dig.ShowDialog();

path = dig.SelectedPath;

ResetList();

}

На рис. 16.25 показано диалоговое окно в действии.

Когда пользователь выбирает каталог, мы соответственно обновляем наше внутреннее поле, перезагружаем новый путь в класс DirectorylmageList, а затем сбрасываем свойство DataContext нашего окна. Это превосходный пример того, насколько просто использовать внутри WPF другие технологии и библиотеки классов .NET. При помощи добавления в наш проект соответствующих пространств имен и ссылок мы просто создаем экземпляр этого класса точно так же, как и любого другого класса в нашем решении. Описание: image437Описание: image438

Совет

Поскольку в WPF и WinForms существует большое количество элементов управле­ния, имеющих одинаковые имена (один такой пример— это ListBox), то (если вы будете использовать классы из библиотек System, windows, controls и System.windows.Forms) вам придется указывать полностью квалифицированные имена некоторых объектов (во избежание использования неверного класса).

Теперь наше приложение функционально завершено. Текущее состояние кода XAML и файла выделенного кода мы приводим в листингах 16.3 и 16.4 соответственно. Однако если вы действительно хотите подробно исследовать это приложение, то вам следует скачать его исходный код с Web-сайта данной книги. Это позволит вам увидеть все улучшения, сделан­ные при помощи графических ресурсов, которые привели к окончательной версии, показан­ной на рис. 16.26.

<Window х:Class="ImageViewer.Windowl"

xmlns="http: //schemas .microsoft. com/winfx/2006/xaml/presentation" xmlns :x="http: //schemas .microsoft. com/winfx/2006/xaml" Title="Windowl" Height="464" Width="545">

<Window.Resources>

<DataTemplate x:Key="ImageDataTemplate">

dmage Source="{Binding UriSource.LocalPath}" Width="125M

Height="125fl />

</DataTemplate>

</Window.Resources>

<Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition Width^'lSO" />

<ColumnDefinition Width="378*" />

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition Height="30" />

<RowDefinition Height="352*" />

<RowDefinition Height=H45n />

</Grid.RowDefinitions>

<Menu Grid.Row="0" Grid.ColumnSpan=H2" Height="22" Name="menul"

VerticalAlignment="Top">

<MenuItem Header="_Folder">

<MenuItem Header=M_Open..." Click=,,FolderOpenMenuItem_Click" /> </MenuItem>

</Menu>

<ListBox SelectionChanged=MlistBoxl_SelectionChangedH Grid.Row="l" Name="listBoxl" ItemsSource="{Binding}"

ItemTemplate="{StaticResource ImageDataTemplate}"/>

cimage Grid.Column="l" Grid.Row="l" Name="image!" Stretch="Fill" />

<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"

Grid.Column="l" Grid.Row="2" Name="stackPanell">

<Button BorderThickness="0" Click="buttonBandW_Click"

Margin="20,0,0,0" Height="23" Name="buttonBandW" Width="30"> Button </Button>

<Button Click="buttonBlur_Click" Margin="20,0,0,0" Height="23"

Name="buttonBlur" Width="30">Button</Button> <Button Click="buttonRotate_Click" Margin="20,0,0,0" Height="23"

Name="buttonRotate" Width="30">Button</Button> <Button Click="buttonFlip_Click" Margin="20,0,20,0" Height="23"

Name="buttonFlip" Width="30">Button</Button>

</StackPanel>

</Grid>

</Window>

Cusing System;

using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Forms; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Effects; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes;

namespace ImageViewer

III <summary>

III Логика взаимодействия для Windowl.xaml III </summary>

public partial class Windowl : Window {

private DirectoryImageList _imgList; private string _path =

Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

public Windowl()

{

InitializeComponent();

ResetList();

this.DataContext = _imgList.Images;

\

private void FolderOpenMenuItem_Click(object sender, RoutedEventArgs e)

{

SetPath();

}

private void SetPath()

I

FolderBrowserDialog dig = new FolderBrowserDialog();

dig.ShowDialog() ;

path = dig.SelectedPath;

ResetList();

}

private void ResetList ()

{

if (IsValidPath(_path))

{

imgList = new DirectorylmageList(_path);

}

this.DataContext = _imgList.Images;

}

private bool IsValidPath(string path)

{

try

{

string folder = System.10.Path.GetFullPath(path); return true;

}

catch

{

return false;

}

}

private void buttonBandW_Click(object sender, RoutedEventArgs e)

{

BitmapSource img = (BitmapSource)image1.Source;

imagel.Source = new FormatConvertedBitmap(img, PixelFormats.Grayl6,

BitmapPalettes.Gray256, 1.0);

}

private void buttonBlur_Click(object sender, RoutedEventArgs e)

{

if (imagel.BitmapEffeet != null)

{

// Если текущий эффект — размытие, удалить imagel.BitmapEffeet = null;

}

else

{

// В противном случае добавить в изображение размытие imagel.BitmapEffeet = new BlurBitmapEffeet();

}

private void buttonRotate_Click(object sender, RoutedEventArgs e)

{

CachedBitmap cache = new CachedBitmap ( (BitmapSource) imagel. Source,

BitmapCreateOptions.None, BitmapCacheOption.OnLoad); imagel.Source = new TransformedBitmap(cache, new RotateTransform(90) ) ;

}

private void buttonFlip_Click(object sender, RoutedEventArgs e)

{

CachedBitmap cache = new CachedBitmap((BitmapSource)imagel.Source,

BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

ScaleTransform scale = new ScaleTransform(-1, -1,

imagel.Source.Width / 2, imagel.Source.Height / 2);

imagel.Source = new TransformedBitmap(cache, scale);

}

private void listBoxl_SelectionChanged(object sender,

SelectionChangedEventArgs e)

{

imagel.Source = (BitmapSource)

((sender as System.Windows.Controls.ListBox).Selectedltem) ;

)

)

}

Подробнее в этой категории: « .NET фирма Microsoft Резюме »
Резюме
.NET фирма Microsoft
Платформа Windows Presentation Foundation
Модель программирования
Простота синтаксиса

Добавить комментарий


Защитный код
Обновить

© 2017 www.visualstudios.ru. Все права защищены.