Вы зашли как: Гость
Опрос
Верите ли вы в скорый выход Surface Phone?

Начала Metro-программирования: списки и поиск файлов (ч.2)

Напечатать страницу
09.07.2012 15:57 | dronov_va

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


6. Получение сведений о файлах и папках
Так, список файлов и папок мы получили. Теперь давайте узнаем, как получить сведения об отдельном файле или папке — имя, расширение, размер, дату создания и изменения и пр., - а также его или её миниатюру.

6.1. Получение основных сведений о файле
Объект Windows.Storage.StorageFile, представляющий в платформе Metro файл, поддерживает ряд свойств, которые позволят нам узнать различные параметры этого файла. Самые полезные из этих свойств перечислены далее:

  • name — имя файла с расширением в виде строки;
  • displayName — имя файла без расширения в виде строки;
  • fileType — расширение файла с начальной точкой в виде строки;
  • path — полный путь к файлу в виде строки/ Отметим, что путь есть не у всех папок; так, у основных папок библиотек путей нет;
  • dateCreated — дата и время создания файла в виде экземпляра объекта Date;
  • displayType — наименование типа файла в виде строки;
  • contentType — MIME-тип файла в виде строки.


var sFileName = arrFiles[0].name;


Получаем имя первого файла из полученного ранее списка.

А метод getBasicPropertiesAsync запускает процесс получения остальных параметров файла — его размера и даты последнего изменения. Он не принимает параметров, а в качестве результата возвращает обязательство, для которого мы с помощью метода then укажем функцию, что выполнится, когда параметры файла будут получены.

Данная функция получит в качестве параметра экземпляр объекта Windows.Storage.FileProperties.BasicProperties, представляющий остальные параметры файла. Нас интересуют следующие свойства этого объекта:

  • size — размер файла в байтах в виде целого числа;
  • dateModified — дата и время последнего изменения файла в виде экземпляра объекта Date.


var iFileSize;
arrFiles[0].getBasicPropertiesAsync().then(function(properties) {
  iFileSize = properties.size;
});


Получаем размер первого файла из полученного ранее списка.

6.2. Получение миниатюры файла и вывод её на экран
Многие приложения, выводящие список файлов, против каждой позиции отображают небольшое изображение — миниатюру. Такой миниатюрой может быть содержимое графического файла или файла документа, первый кадр видеофайла или какое-либо стороннее изображение, обозначающее данный тип файлов.

Ранее, чтобы получить миниатюру файла, разработчик должен был писать довольно громоздкий код. Но нам этого делать не придётся — платформа Metro предоставляет встроенные средства для получения миниатюры файла, исключительно гибкие и при этом простые в использовании.

Объект Windows.Storage.StorageFile, представляющий файл, поддерживает метод getThumbnailAsync, который запускает процесс получения миниатюры данного файла. Формат его вызова таков:

<файл>.getThumbnailAsync(
  <вид миниатюры>[,
  <ширина миниатюры>[,
  <параметры миниатюры>]]
)

t;параметры миниатюры>]]
)[/code]
Единственный обязательный параметр этого метода задаёт вид получаемой миниатюры в виде одного из элементов перечисления Windows.Storage.FileProperties.ThumbnailMode:

  • picturesView — миниатюра размером 190*130 пикселов для списка графических файлов.
  • videosView — миниатюра размером 190*130 пикселов для списка видеофайлов (представляет собой первый кадр фильма).
  • musicView — миниатюра размером 40*40 пикселов для списка звуковых файлов (либо обложка альбома, либо, если она отсутствует, некое стороннее изображение).
  • documentsView — миниатюра размером 40*40 пикселов для списка файлов документов (либо первая страница содержимого, либо сохранённая в файле миниатюра, если она есть).

    На заметку
    При указании любого из этих элементов мы получим миниатюру, оптимизированную для использования в списке Metro, который выводит пункты сначала по вертикали, а потом — по горизонтали с горизонтальной прокруткой. (Подробнее о списках Metro мы поговорим позже).
  • listView — миниатюра размером 40*40 пикселов, оптимизированная для списка Metro, который выводит свои пункты по вертикали с вертикальной прокруткой.
  • singleItem — большая миниатюра, оптимизированная для использования в качестве отдельного элемента интерфейса. Минимальный размер самой длинной стороны такой миниатюры равен 256 пикселов.


Вторым, необязательным, параметром указывается размер самой длинной стороны получаемой миниатюры в виде целого числа в пикселах. Если этот параметр опущен, будет создана миниатюра с размерами по умолчанию.

Третьим, также необязательным, параметром задаются дополнительные параметры получаемой миниатюры. Они указываются в виде одного из элементов перечисления Windows.Storage.FileProperties.ThumbnailOptions:

  • none — дополнительные параметры отсутствуют;
  • returnOnlyIfCached — возвращать только миниатюры, либо хранящиеся в самом файле, либо те, что уже находятся в системном кэше миниатюр Windows. Если таковые отсутствуют, миниатюра не будет сформирована;
  • resizeThumbnail — увеличить или уменьшить миниатюру, полученную из файла или системного кэша, чтобы она вписалась в указанные нами размеры;
  • useCurrentScale — увеличить миниатюру, полученную из файла или системного кэша, соответственно разрешающей способности экрана (поведение по умолчанию).


Метод getThumbnailAsync возвращает в качестве результата обязательство, для которого мы в вызове метода then укажем функцию. Эта функция будет выполнена по завершении процесса получения миниатюры и получит в качестве параметра следующее:

  • либо представляющий эту миниатюру экземпляр объекта Windows.Storage.FileProperties.StorageItemThumbnail, если миниатюру удалось получить;
  • либо значение null, если её получить не удалось.


Теперь нам нужно как-то вывести полученную миниатюру на экран. Если мы используем для создания Metro-приложения "связку" технологий HTML, CSS и JavaScript, то можем применить для этого хорошо знакомый нам тег <img>. Мы укажем в его атрибуте src ссылку на изображение, которое требуется вывести, то есть нашу миниатюру.

Но как получить эту ссылку? Представляющий миниатюру объект Windows.Storage.FileProperties.StorageItemThumbnail не поддерживает ни свойства, ни метода, который позволил бы нам до неё добраться. А экземпляры этого объекта не поддерживаются тегом <img>...

Решить эту проблему нам поможет метод createObjectURL объекта URL. (Объект URL предоставляет различные инструменты для работы с файлами и ссылками на них. Единственный его экземпляр создается самой платформой Metro и доступен через переменную URL.) В качестве единственного параметра он принимает миниатюру и возвращает представляющий его экземпляр особого объекта Blob. Последний можно рассматривать как массив данных, хранящий содержимое данного файла и представленный в виде, который поддерживается всеми элементами интерфейса Metro, в том числе и тегом <img>. То, что нам и нужно!

[code]<img id="imgThumbnail" />
. . .
var imgThumbnail = document.getElementById("imgThumbnail");
arrFiles[0].getThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.singleItem, 512,
Windows.Storage.FileProperties.ThumbnailOptions.resizeThumbnail).then(function(thumbnail) {
imgThumbnail.src = URL.createObjectURL(thumbnail);
});[/code]
Получаем миниатюру первого файла из полученного ранее списка и выводим её на экран. Для миниатюры мы задаём вид, оптимизированный для вывода в качестве отдельного элемента интерфейса, размер длинной стороны в 512 пикселов и масштабирование под указанный нами размер.

6.3. Получение сведений о папке и миниатюры содержимого папки
Объект Windows.Storage.StorageFolder, который представляет папку, поддерживает ряд свойств, позволяющих нам узнать основные параметры этой папки. Это уже знакомые нам свойства displayName, name, path, dateCreated и properties.

Помимо этого, платформа Metro позволяет нам получить миниатюру всего содержимого папки. Такая миниатюра представляет собой набор миниатюр отдельных файлов, хранящихся в папке, которые выглядят как сложенные в "стопку".

Получение миниатюры содержимого папки выполняется с помощью того же метода getThumbnailAsync, который на этот раз вызывается у папки.

[code]<img id="imgThumbnail" />
. . .
var imgThumbnail = document.getElementById("imgThumbnail");
oFP.pickSingleFolderAsync().then(function(folder) {
if (folder) {
folder.getThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.singleItem, 512).then(function(thumbnail) {
imgThumbnail.src = URL.createObjectURL(thumbnail);
});
}
});[/code]
Получаем миниатюру папки, выбранной пользователем.


7. Списки Metro
Так, список файлов, хранящийся в папке, мы получили. Теперь его нужно вывести на экран в виде перечня отдельных позиций, отформатированных нужным образом, и дать пользователю возможность выбрать какую-либо позицию, чтобы просмотреть содержимое соответствующего ей файла.

Платформа Metro предоставляет нам для этого все нужные инструменты. А именно - списки Metro.

7.1. Создание списка Metro
Список Metro является элементом управления Metro и представляется объектом WinJS.UI.ListView. Имя этого объекта нам следует указать в качестве значения для атрибута data-win-control тега <div>, что создаст для него элемент-основу.

[code]<div id="divList" data-win-control="WinJS.UI.ListView"></div>[/code]
По умолчанию список Metro выстраивает свои пункты сначала по вертикали, а потом — по горизонтали и при необходимости обеспечивает их прокрутку по горизонтали. Получается нечто похожее на таблицу, которая заполняется сначала по столбцам, а потом — по строкам.

Однако мы можем изменить это поведение, воспользовавшись свойством layout объекта WinJS.UI.ListView. В качестве значения оно принимает экземпляр одного из объектов, перечисленных далее:

  • экземпляр объекта WinJS.UI.GridLayout указывает списку выстроить пункты сначала по вертикали, потом — по горизонтали с горизонтальной же прокруткой (вывод в виде таблицы; поведение по умолчанию);
  • экземпляр объекта WinJS.UI.ListLayout указывает списку выстроить пункты по вертикали и реализовать вертикальную прокрутку (вывод в виде списка). При этом список Metro выглядит более традиционно.


[code]var ctrList = document.getElementById("divList").winControl;
ctrList.layout = new WinJS.UI.ListLayout();[/code]
Но в большинстве случаев удобнее указать расположение пунктов списка прямо в теге <div>, который создаёт элемент-основу. (Как мы знаем из предыдущей статьи цикла "Начала Metro-программирования", для указания параметров элемента управления Metro применяется атрибут тега data-win-options.) Но как задать в качестве значения для свойства списка экземпляр объекта?

С помощью записи вот такого формата:

[code]<имя свойства>: {type: <имя объекта>}[/code]
Имя объекта, на основе которого будет создан экземпляр, указывается без кавычек.

[code]<div id="divList" data-win-control="WinJS.UI.ListView"
data-win-options="{layout: {type: WinJS.UI.ListLayout}}"></div>[/code]
А свойство selectionMode объекта WinJS.UI.ListView позволит нам указать режим выбора пунктов в списке. Оно поддерживает три предопределённых значения, которые должны быть указаны в виде строк:

  • none — пользователь не сможет выбрать ни один пункт в списке;
  • single — пользователь сможет выбрать только один пункт;
  • multi — пользователь может выбрать произвольное количество пунктов (поведение по умолчанию).


[code]<div id="divList" data-win-control="WinJS.UI.ListView"
data-win-options="{selectionMode: 'single'}"></div>[/code]
Для задания режима выбора пунктов в коде логики удобнее использовать перечисление WinJS.UI.SelectionMode. Поддерживаемые им элементы none, single и multi соответствуют перечисленным ранее строковым значениям.

[code]ctrList.selectionMode = WinJS.UI.SelectionMode.single;[/code]
7.2. Создание пунктов списка
Пустой, не содержащий пунктов список никому не нужен. Поэтому следующим нашим шагом будет заполнение готового списка Metro пунктами.

7.2.1. Подготовка массива данных
Данные, которые будут выводиться в списке Metro, должны представлять собой массив (он так и называется - массив данных). И формируется он по особым правилам:

  • каждый элемент массива данных представляет один пункт списка;
  • каждый элемент массива данных должен хранить экземпляр объекта Object;
  • каждый экземпляр объекта Object, хранящийся в массиве данных, должен включать набор свойств, которые будут хранить отдельные значения, выводимые в пункте списка.


[code]var arrNews = [];
arrNews[0] = {
date: new Date(2012, 1, 17),
header: "Microsoft рассказала о ReFS, новой файловой системе Windows Server 8",
content: "В своем блоге B8 компания Microsoft поделилась информацией о новой файловой системе Windows Server 8, известной под названием ReFS и призванной заменить NTFS, которая используется в Windows с 1993 года."
};[/code]
Здесь мы объявили согласно приведённым ранее правилам массив данных arrNews и создали первый его элемент, представляющий новость из канала RSS. Как видим, каждая новость включает в свой состав дату публикации (свойство date), заголовок (свойство header) и содержимое (свойство content).

7.2.2. Создание источника данных, получение адаптера и привязка его к списку
Итак, массив данных готов. Можно создавать на его основе источник данных — особую структуру, которая позволит списку получать из массива данные и формировать на их основе пункты.

Источник данных представляется объектом WinJS.Binding.List. Нам следует создать экземпляр этого объекта, передав ему в качестве параметра созданный ранее массив данных:

[code]var dsrNews = new WinJS.Binding.List(arrNews);[/code]
Далее мы обратимся к свойству dataSource созданного источника данных, чтобы получить так называемый адаптер. Это экземпляр особого объекта, который можно рассматривать как посредник между источником данных и списком.

Останется только привязать полученный адаптер к списку Metro — и дело сделано. Для этого достаточно присвоить адаптер свойству itemDataSource списка.

[code]ctrList.itemDataSource = dsrNews.dataSource;[/code]
После этого список сам сформирует пункты на основе указанных нами данных и выведет их на экран.

7.2.3. Использование шаблонов для оформления пунктов списка
Только пункты этого списка будут содержать совсем не то, что нам нужно. А именно — исходный код на языке JavaScript, с помощью которого мы создали соответствующие этим пунктам элементы массива данных.

Дело в том, что список Metro не "знает", какие значения из элемента массива данных, описывающего пункт, ему следует вывести на экран и какой формат для этого применить. Поэтому он поступает по умолчанию — преобразует каждый элемент массива в текстовое представление, то есть в JavaScript-код, который его формирует.

Так что нам придётся указать формат, в котором список Metro будет формировать свои пункты. Или, если придерживаться терминологии Metro, задать для списка шаблон — описание этого формата.

Шаблон Metro можно описать на языке HTML прямо в файле, где хранится код интерфейса приложения (это файл default.html). HTML-код, создающий шаблон, обязательно должен находиться перед кодом, формирующим список, к которому он будет привязан; в противном случае список его не "найдёт".

Шаблон — это особый элемент управления Metro. Он создается так же, как остальные элементы управления Metro, и представляется объектом WinJS.Binding.Template.

[code]<div id="divListTemplate" data-win-control="WinJS.Binding.Template">
</div>[/code]
Внутри элемента-основы шаблона формируются элементы интерфейса, в которых, собственно, и будут выводиться необходимые данные. Теги, формирующие эти элементы интерфейса, должны быть пустыми.

Для каждого из этих элементов интерфейса нам потребуется указать два свойства. Во-первых, свойство экземпляра объекта Object — элемента массива данных, откуда будет взято значение, что будет выводиться в этом элементе. Во-вторых, свойство самого элемента интерфейса, которому будет присвоено данное значение. Например, значение свойства header элемента массива данных мы можем присвоить свойству textContent текстового абзаца (оно представляет текстовое содержимое элемента интерфейса), а значение свойства src элемента массива данных, хранящего интернет-адрес файла с изображением, — свойству src элемента — графического изображения.

Эти свойства мы укажем в атрибуте тега data-win-bind, значение которого записывается в следующем формате:

[code]<свойство элемента интерфейса>: <свойство экземпляра объекта Object — элемента массива данных>[/code]
[code]<div id="divListTemplate" data-win-control="WinJS.Binding.Template">
<p data-win-bind="textContent: date"></p>
<p data-win-bind="textContent: header"></p>
</div>[/code]
Здесь мы создали шаблон с двумя абзацами. Свойству textContent первого из них будет присвоено значение свойства date элемента массива данных, в результате чего данный абзац получит в качестве текстового содержимого дату публикации новости, которая перед выводом будет автоматически преобразована в строковый вид. А во втором абзаце будет выведен заголовок новости (значение свойства header элемента массива данных).

Мы можем задать оформление для элементов интерфейса, входящих в шаблон, привязав к ним стили.

[code]<div id="divListTemplate" data-win-control="WinJS.Binding.Template">
<p data-win-bind="textContent: date" class="new-date"></p>
<p data-win-bind="textContent: header" class="new-header"></p>
</div>
. . .
.new-date { text-align: right; }
.new-header { font-size: 12pt; }[/code]
Здесь мы указали для абзаца с датой публикации выравнивание текста по правому краю, а для абзаца с заголовком — размер шрифта в 12 пунктов.

Осталось лишь привязать готовый шаблон к списку. Для этого достаточно присвоить имя его элемента-основы свойству itemTemplate списка:

[code]<div id="divList" data-win-control="WinJS.UI.ListView"
data-win-options="{itemTemplate: divListTemplate}"></div>[/code]
Отметим две вещи. Во-первых, мы присваиваем этому свойству имя элемента-основы шаблона; получив его, список Metro сам "отыщет" созданный на его основе шаблон. Во-вторых, мы указываем это имя без кавычек.

Вот теперь наш список будет выводить то, что нам нужно.

Ещё платформа Metro позволяет создать шаблон в виде функции (так называемый шаблон-функцию). Эта функция будет формировать пункты списка программно.

Единственным параметром, принимаемым данной функцией, станет обязательство. Для этого обязательства мы в вызове метода then укажем функцию, которая в качестве параметра получит экземпляр объекта Object, представляющий формируемый пункт. Его свойство data, в свою очередь, будет хранить экземпляр объекта Object — соответствующий данному пункту элемент массива данных.

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

Помимо этого, сама шаблон-функция должна вернуть в качестве результата обязательство, что она получила как параметр.

Лучше один раз увидеть, чем сто раз услышать. Поэтому давайте рассмотрим пример шаблона-функции.

[code]function listTemplate(itemPromise) {
return itemPromise.then(function(item) {
var oItem = item.data;
var oDiv = document.createElement("div");
var oP = document.createElement("p");
oP.className = "new-date";
oP.textContent = oItem.date.getDate() + "." +
(oItem.date.getMonth() + 1) + "." + oItem.date.getFullYear();
oDiv.appendChild(oP);
oP = document.createElement("p");
oP.className = "new-header";
oP.textContent = oItem.header;
oDiv.appendChild(oP);
return oDiv;
});
}[/code]
Для формирования значения даты в привычном нам формате <число>.<месяц>.<год> мы использовали три метода объекта Date. Метод getDate возвращает число, метод getMonth — номер месяца от 0 до 11 (январь — декабрь), а метод getFullYear — год в "полном" формате (четыре цифры). Все они не принимают параметров и возвращают результат в виде целого числа.

Осталось только привязать готовый шаблон-функцию к списку. Сделать это можно только в коде логики.

[code]ctrList.itemTemplate = listTemplate;[/code]
Шаблон-функция имеет перед обычным, описанным в HTML-коде шаблоном определённые преимущества. Во-первых, мы можем использовать в таком шаблоне значения, полученные в результате каких-либо вычислений (так, в приведённом ранее примере мы вычисляли значение даты в привычном нам формате). Во-вторых, в зависимости от выполнения какого-либо условия мы можем менять содержимое пунктов списка. В HTML-шаблоне ничего этого сделать не получится.

7.2.4. Фильтрация пунктов списка
Источник данных предоставляет нам интересную и полезную возможность — фильтрацию пунктов списка. То есть вывод в списке только тех пунктов, что удовлетворяют определённому условию — критерию фильтрации.

Если мы хотим реализовать в своем списке фильтрацию, нам не обойтись без метода createFiltered источника данных.

[code]<источник данных>.createFiltered(
<функция, задающая критерий фильтрации>
)[/code]
Единственным параметром он принимает функцию, которая реализует критерий фильтрации. В качестве единственного параметра данная функция примет экземпляр объекта — элемент массива данных, а вернёт логическое значение: true, если данный элемент должен быть выведен в списке, и false, если не должен.

Метод createFiltered возвращает в качестве результата новый источник данных — уже отфильтрованный.

[code]var oDate = new Date(2012, 2, 17);
function filterList(item) {
return (item.date.getTime() == oDate.getTime());
}
var dsrFiltered = dsrNews.createFiltered(filterList);
ctrList.itemDataSource = dsrFiltered.dataSource;[/code]
Выводим в списке только новости, опубликованные 17 января 2012 года.

Метод getTime объекта Date возвращает количество миллисекунд, прошедших между значением даты и полночью 1 января 1970 года. Фактически он позволяет получить числовое представление даты, которое можно использовать в операциях сравнения (что мы и сделали).

Самое интересное, что фильтрация, которую мы реализуем, не затронет сам массив данных. Это значит, что все элементы, не удовлетворяющие заданному нами критерию фильтрации, хоть и не будут присутствовать в новом источнике данных, но всё же останутся в составе массива.

7.2.5. Сортировка пунктов списка
Другая возможность, предоставляемая нам источником данных Metro — сортировка пунктов списка. Отсортированные по какому-либо критерию списки легче читаются.

Выполнить сортировку нам поможет метод createSorted источника данных.

[code]<источник данных>.createSorted(
<функция сравнения>
)[/code]
Единственным параметром этому методу передаётся так называемая функция сравнения. Она принимает два параметра — два сравниваемых элемента массива данных — и возвращает в качестве результата:

  • отрицательное число, если первый элемент "меньше" второго;
  • 0, если оба этих элемента "равны";
  • положительное число, если первый элемент "больше" второго.


Метод createSorted возвращает в качестве результата новый — отсортированный — источник данных.

[code]function compareItems(item1, item2) {
return item1.date.getTime() - item2.date.getTime();
}
var dsrSorted = dsrNews.createSorted(compareItems);
ctrList.itemDataSource = dsrSorted.dataSource;[/code]
Выводим в списке новости, отсортированные по дате публикации.

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

Сортировка, что мы реализуем в источнике данных, также не будет затрагивать исходный массив данных.


Дополнительные материалы


Окончание следует...


dronov_va, TheVista.Ru Team
Июль 2012

Комментарии

Комментариев нет...
Для возможности комментировать войдите в 1 клик через

По теме

Акции MSFT
100.4 0.00
Акции торгуются с 17:30 до 00:00 по Москве
Мы на Facebook
Мы ВКонтакте
Все права принадлежат © MSInsider.ru (ex TheVista.ru), 2017
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.048 секунд (Общее время SQL: 0.009 секунд - SQL запросов: 31 - Среднее время SQL: 0.00028 секунд))