Окончание статьи, посвящённой реализации поиска данных в Metro-приложениях.
4. Реализация подсказок для поиска
Многие приложения, требующие ввести какие-либо данные, например, ключевое слово для поиска, предусматривают возможность вывода подсказок. Эти подсказки выводятся в виде списка, появляющегося ниже соответствующего поля ввода, как только пользователь устанавливает в нём текстовый курсор, и представляют собой значения, либо введённые пользователем ранее, либо сгенерированные самим приложением на основе каких-то критериев. Классический пример таких подсказок - список введённых ранее интернет-адресов, перечисляемых Web-обозревателем при вводе очередного интернет-адреса.
Платформа Metro предоставляет исключительно простые и гибкие средства для реализации подобных подсказок. Сейчас мы с ними познакомимся.
4.1. Формирование подсказок на основе ключевых слов, введённых ранее
Проще всего реализовать поддержку подсказок, представляющих собой введённые ранее пользователем ключевые слова. Для этого достаточно присвоить свойству searchHistoryEnabled объекта Windows.ApplicationModel.Search.SearchPane значение true.
oSearchPane.searchHistoryEnabled = true;
По умолчанию же это свойство имеет значение false, то есть изначально приложение не формирует подсказки на основе ранее введённых ключевых слов.
Как только мы активизируем формирование таких подсказок, платформа Metro сама будет сохранять введённые ранее ключевые слова на диске, сама будет извлекать их и сама же будет выводить на экран. Никаких дополнительных действий для этого нам выполнять не придётся.
По умолчанию платформа Metro сохраняет все введённые ранее ключевые слова в одной "куче". Однако мы можем разбить эту "кучу" на различные группы, что может пригодиться в приложениях, оперирующих разнородными данными. Например, приложение для чтения каналов новостей может указать разные группы для сохранения ключевых слов, относящихся к собственно каналам новостей и отдельным новостям, находящимся в выбранном канале.
Объект Windows.ApplicationModel.Search.SearchPane поддерживает свойство searchHistoryContext. Оно как раз и служит для задания имени группы сохранённых всплывающих подсказок, которое указывается в виде строки. Имя группы может быть произвольным.
oSearchPane.searchHistoryContext = "feeds";
Теперь все введённые ключевые слова будут сохраняться в группе с именем feeds.
oSearchPane.searchHistoryContext = "news";
А теперь - в группе news.
Чтобы вернуть поведение по умолчанию, когда все введённые ранее ключевые слова сохраняются в одной "куче" без разбиения на группы, достаточно присвоить свойству searchHistoryContext значение null.
oSearchPane.searchHistoryContext = null;
4.2. Формирование подсказок на основе имён файлов
Ещё одна интересная возможность, предлагаемая платформой Metro, - формирование подсказок на основе имён файлов, хранящихся в какой-либо папке или папках. Она может быть полезной, если мы разрабатываем приложение, работающее с файлами.
Сначала нам потребуется создать экземпляр объекта Windows.ApplicationModel.Search.LocalContentSuggestionSettings, который будет просматривать содержимое указанных нами папок и формировать на основе имён хранящихся там файлов подсказки для поиска. Создаётся этот экземпляр объекта хорошо известным нам способом - с помощью оператора new. Параметров его конструктор не принимает.
var oLCSS = new Windows.ApplicationModel.Search.LocalContentSuggestionSettings();
Далее мы зададим для свойства enabled полученного экземпляра объекта значение true, активизировав тем самым формирование подсказок на основе имён файлов. Значение этого свойства по умолчанию - false; это значит, что изначально такие подсказки не формируются.
oLCSS.enabled = true;
Следующий наш шаг - указание папок, из которых будут браться файлы для формирования подсказок. Здесь нам понадобится свойство locations объекта Windows.ApplicationModel.Search.LocalContentSuggestionSettings.
Значением этого свойства является экземпляр особого объекта-коллекции, хранящего список папок. Эта коллекция реализует интерфейс IVector, который типизирован для хранения списка папок - экземпляров объекта StorageFolder. Изначально эта коллекция пуста, и нам потребуется её заполнить.
Метод append добавляет в коллекцию новую папку. В качестве единственного параметра он принимает экземпляр объекта StorageFolder, предсталяющего папку в платформе Metro, и не возвращает результата.
Добавляем в список папок основную папку системной библиотеки Изображения.
Метод clear коллекции папок позволяет очистить список. Он не принимает параметров и не возвращает результата.
oLCSS.locations.clear();
По умолчанию платформа Metro формирует подсказки на основе имён всех файлов, что хранятся в указанных нами папках. Но мы можем отобрать для формирования подсказок только файлы, удовлетворяющие заданному нами критерию - фильтру. Такой фильтр записывается на языке AQS (Advanced Query Syntax, расширенный синтаксис запроса) в виде строки и присваивается свойству aqsFilter объекта-коллекции папок.
На заметку Полное описание языка AQS можно найти на этой Web-странице.
oLCSS.aqsFilter = "date:this week";
Этот фильтр задаёт отбор только тех файлов, что были созданы на текущей неделе.
Последнее, что нам требуется сделать, - привязать экземпляр объекта Windows.ApplicationModel.Search.LocalContentSuggestionSettings, формирующий подсказки, к панели Поиск. Выполняется это вызовом метода setLocalContentSuggestionSettings панели. В качестве единственного параметра этот метод принимает упомянутый ранее экземпляр объекта и не возвращает результата.
Ещё мы имеем возможность создать свои собственные подсказки. Это могут быть подсказки, сгенерированные самим приложением либо полученные из какого-либо внешнего источника, например, локального файла или интернет-сервиса.
Панель Поиск поддерживает событие suggestionsrequested, возникающее, когда платформа Metro собирается вывести на экран список подсказок. В обработчике этого события мы можем указать произвольные подсказки, которые будут добавлены в этот список.
Функция - обработчик данного события принимает в качестве единственного параметра экземпляр объекта Windows.ApplicationModel.Search.SearchPaneSuggestionsRequestedEventArgs, хранящий сведения о возникшем событии. Этот объект поддерживает свойство queryText, которое хранит значение, введённое пользователем в поле ввода ключевого слова. Мы можем использовать его для вывода только тех подсказок, которые начинаются с введённых пользователем символов.
А ещё он поддерживает свойство request. Оно хранит экземпляр объекта Windows.ApplicationModel.Search.SearchPaneSuggestionsRequest, в котором и указываются формируемые нами подсказки.
Объект Windows.ApplicationModel.Search.SearchPaneSuggestionsRequest поддерживает свойство searchSuggestionCollection. Его значением является экземпляр объекта-коллекции Windows.ApplicationModel.Search.SearchSuggestionCollection, хранящий список созданных нами подсказок. Вот в эту-то коллекцию мы и будем добавлять наши подсказки.
Здесь сразу нужно заметить, что платформа Metro позволяет выводить два вида произвольных подсказок. Рассмотрим их.
Подсказки поиска - позволяют пользователю завершить набираемое ключевое слово. При выборе такой подсказки приложение выполняет обычный поиск, как если бы пользователь ввёл ключевое слово вручную.
Подсказки результатов - фактически представляют собой готовые, предопределённые в приложении результаты поиска. При выборе такой подсказки приложение выводит результаты, полученные при выполнении такого предопределённого поиска. В качестве примера такой подсказки можно привести нечто наподобие "Вывести файлы, созданные в течение текущей недели".
Мы можем создать не более пяти произвольных подсказок, относящихся к обоим видам. Если мы собираемся создать и подсказки поиска, и подсказки результатов, то должны будем разделить их особым разделителем. Отметим, что разделитель также считается подсказкой, то есть занимает одну позицию в списке.
Объект-коллекция Windows.ApplicationModel.Search.SearchSuggestionCollection поддерживает четыре метода, позволяющие добавить подсказку того или иного вида. Все эти методы не возвращают результата.
appendQuerySuggestion - добавляет в список одну подсказку поиска. Текст подсказки в виде строки передаётся данному методу единственным параметром.
appendQuerySuggestions - добавляет в список сразу несколько подсказок поиска. Единственным параметром он принимает массив, элементы которого представляют собой добавляемые подсказки и должны быть уазаны в виде строк.
appendResultSuggestion - добавляет в список одну подсказку результата. Формат вызова этого метода таков:
Первым и вторым параметрами передаются, соответственно, текст подказки, который будет выведен в списке, и её описание. Оба эти значения должны представлять собой строки.
Третьим параметром передаётся [i]тег подсказки[/i] - строковое значение, уникально её идентифицирующее. По этому тегу приложение может выяснить, какую подсказку результата выбрал пользователь.
Четвёртым параметром передаётся графическое изображение, которое будет выведено в составе данной подсказки. Оно должно представлять собой экземпляр объекта Windows.Storage.Streams.RandomAccessStreamReference.
Этот экземпляр объекта получается в два этапа. На первом этапе мы формируем строку со ссылкой на нужный графический файл и создаём экземпляр объекта Windows.Foundation.Uri, передав конструктору данного объекта полученную строку. (Объект Windows.Foundation.Uri представляет ссылку на файл, хранящийся на локальном диске или в Интернете.)
[code]var s = "/images/result_suggestion.png";
var oURL = new Windows.Foundation.Uri(s);
аве данной подсказки. Оно должно представлять собой экземпляр объекта Windows.Storage.Streams.RandomAccessStreamReference.
Этот экземпляр объекта получается в два этапа. На первом этапе мы формируем строку со ссылкой на нужный графический файл и создаём экземпляр объекта Windows.Foundation.Uri, передав конструктору данного объекта полученную строку. (Объект Windows.Foundation.Uri представляет ссылку на файл, хранящийся на локальном диске или в Интернете.)
var s = "/images/result_suggestion.png";
var oURL = new Windows.Foundation.Uri(s);
На втором этапе мы вызываем метод createFromUri объекта Windows.Storage.Streams.RandomAccessStreamReference, передав ему в качестве единственного параметра полученный ранее экземпляр объекта Windows.Foundation.Uri. В результате мы получим то, что нам и нужно, - экземпляр объекта Windows.Storage.Streams.RandomAccessStreamReference, представляющий изображение, что хранится в данном файле.
var oRASR = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(oURL);
Последний, пятый, параметр метода appendResultSuggestion указывает текст замены для изображения. Он также задаётся в виде строки.
appendSearchSeparator - создаёт разделитель. В качестве результата он принимает текст, используемый в качестве разделителя, который должен быть задан в виде строки.
oSearchPane.addEventListener("suggestionsrequested", function(args) {
var oSC = args.request.searchSuggestionCollection;
oSC.appendQuerySuggestion("image");
oSC.appendQuerySuggestions(["picture", "icon"]);
oSC.appendSearchSeparator("Предопределённые поиски");
var s = "/images/result_suggestion.png";
var oURL = new Windows.Foundation.Uri(s);
var oRASR = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(oURL);
oSC.appendResultSuggestion("За текущую неделю",
"Вывести файлы, созданные в течение текущей недели", "thisweek", oRASR, "Картинка");
});
uot;thisweek", oRASR, "Картинка");
});[/code]
Здесь мы привязываем к событию suggestionsrequested обработчик и в его теле создаём три подсказки поиска, разделитель и подсказку результата.
4.4. Обработка подсказок результатов
Обычные подсказки, в том числе и произвольные подсказки поиска, не требуют какой-либо специальной обработки. В отличие от подсказок результатов. Поэтому, если мы собираемся использовать такие подсказки в своих приложениях, должны узнать, как они обрабатываются.
Панель Поиск поддерживает событие resultsuggestionchosen. Оно возникает, когда пользователь выбирает в списке подсказку результата.
Функция - обработчик этого события принимает в качестве единственного параметра экземпляр объекта Windows.ApplicationModel.Search.SearchPaneResultSuggestionChosenEventArgs. Он хранит дополнительные сведения о возникшем событии.
Сведений этих совсем немного - только тег, заданный нами для подсказки при её создании (см. ранее). Он хранится в свойстве tag данного объекта в виде строки.
[code]oSearchPane.addEventListener("resultsuggestionchosen", function(args) {
var sTag = args.tag;
//Выполняем поиск соответственно выбранной пользователем подсказке
});[/code]
Привязываем к панели Поиск обработчик события resultsuggestionchosen, в его теле получаем тег выбранной подсказки и выполняем соответствующий поиск.
5. Дополнительные возможности панели Поиск
А теперь рассмотрим кое-какие дополнительные возможности, что предоставляет нам панель Поиск платформы Metro. А именно, несколько свойств, методов и событий данной панели, которые могут быть нам полезны.
Прежде всего, мы можем указать для поля ввода ключевого слова текст подсказки. Этот текст будет присутствовать в поле ввода, если оно не имеет фокуса и если пользователь до этого момента ещё ничего туда не ввёл. Текст подсказки задаётся с помощью свойства placeholderText в виде строки.
Здесь мы даём пользователю понять, что от него требуется ввести имя искомого файла.
Метод show позволяет вывести панель Поиск на экран программно, не дожидаясь, пока это сделает пользователь. В качестве единственного необязательного параметра он может принимать строку с ключевым словом, которое должно быть подставлено в поле ввода этой панели. Результата этот метод не возвращает.
[code]oSearchPane.show("image");[/code]
Свойство visible возвращает значение true, если панель Поиск в данный момент присутствует на экране, и false в противном случае.
[code]if (oSearchPane.visible) {
//Панель Поиск присутствует на экране
} else {
//Панель Поиск отсутствует на экране
}[/code]
Событие visibilitychanged возникает, когда панель Поиск появляется на экране или, наоборот, пропадает с него. Его функция-обработчик в качестве единственного параметра принимает экземпляр объекта Windows.ApplicationModel.Search.SearchPaneVisibilityChangedEventArgs. Свойство visible этого объекта возвращает true, если панель появилась на экране, и false в противном случае.
[code]oSearchPane.addEventListener("visibilitychanged", function(args) {
if (args.visible) {
//Панель Поиск появилась на экране
} else {
//Панель Поиск пропала с экрана
}
});[/code]
А событие querychanged возникает, когда пользователь изменяет значение, присутствующее в поле ввода ключевого слова. Функция - обработчик этого события в качестве единственного параметра принимает экземпляр объекта Windows.ApplicationModel.Search.SearchPaneQueryChangedEventArgs. Чьё свойство queryText будет хранить новое значение, присутствующее в поле ввода ключевого слова.
Событие querychanged можно использовать для выполнения "моментального" поиска в процессе ввода ключевого слова. Только поиск этот должен быть действительно очень быстрым.
[code]oSearchPane.addEventListener("querychanged", function(args) {
var keyword = args.queryText;
//Выполняем поиск
});[/code]
6. Приложение просмотровщика графики ImageViewer с возможностью поиска
В качестве практического занятия давайте доработаем приложение просмотровщика графических файлов ImageViewer, созданное в одной из предыдущих статей данного цикла, добавив ему возможность поиска.
Откроем в Visual Studio проект ImageViewer. Сразу же добавим в него контракт поиска (как это сделать, было рассказано в начале этой статьи). И откроем файл default.js, в котором пишется код логики.
Первым делом объявим ещё одну переменную, которая будет хранить введённое пользователем ключевое слово.
[code]var keyword = "";[/code]
Здесь мы изначально присваиваем этой переменной пустую строку, говоря тем самым приложению, что ключевое слово ещё не было введено.
Далее найдём код инициализации (обработчик события DOMContentLoaded) и изменим его следующим образом:
var oSearchPane = Windows.ApplicationModel.Search.SearchPane.getForCurrentView();
oSearchPane.searchHistoryEnabled = true;
var oLCSS = new Windows.ApplicationModel.Search.LocalContentSuggestionSettings();
oLCSS.enabled = true;
oLCSS.locations.append(Windows.Storage.KnownFolders.picturesLibrary);
oSearchPane.setLocalContentSuggestionSettings(oLCSS);
Здесь мы получаем панель Поиск и активизируем для неё подсказки, формируемые на основе введённых ранее ключевых слов и файлов, хранящихся в библиотеке Изображения. Далее мы привязываем к панели обработчик события querysubmitted, который получит ключевое слово, введённое пользователем, предварительно преобразовав его к нижнему регистру, и выполнит заполнение списка файлами, чьи имена содержат это ключевое слово. Преобразование строки к нижнему регистру выполняется вызовом не принимающего параметров метода toLowerCase объекта String (то есть строки).
Отыщем код, привязывающий обработчик к событию activated приложения, и заменим его следующим кодом:
[code]app.onactivated = function (eventObject) {
if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
fillList();
}
if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.search) {
keyword = eventObject.detail.queryText.toLowerCase();
fillList();
}
};[/code]
Внимание! Автор изначально создал это приложение в бета-версии Visual Studio и дорабатывал впоследствии в Release Candidate. Поэтому данный код выполнен в стиле бета-версии. (За подробностями обращайтесь к параграфам 3.1.1.1 и 3.1.1.2.)
Здесь мы сначала проверяем, было ли приложение активизировано в процессе обычного запуска, и, если это так, заполняем список файлами, как обычно. Далее в случае, если приложение было активизировано из панели Поиск, получаем введённое ключевое слово и также заполняем список файлов.
И изменим код тела функции fillList, чтобы он выглядел так:
[code]function fillList() {
divFolderPath.textContent = oCurrentFolder.path;
arrFiles = [];
oCurrentFolder.getFilesAsync().then(function(files) {
if (files.size > 0) {
for (var i = 0; i < files.size; i++) {
if ((keyword === "") || (files.displayName.toLowerCase().indexOf(keyword) > -1)) {
arrFiles.push(files);
}
}
}
dsrFiles = new WinJS.Binding.List(arrFiles);
ctrList.itemDataSource = dsrFiles.dataSource;
});
}[/code]
Здесь мы перед тем, как добавить найденный файл в массив данных, проверяем, было ли введено ключевое слово ИЛИ содержит ли его имя данного файла. В результате, если ключевое слово не было введено, мы получим массив данных, включающий все файлы, а если же оно было введено, массив данных включит только файлы, чьи имена содержат данное ключевое слово.
Метод indexOf объекта String принимает в качестве единственного параметра подстроку и возвращает номер символа в строке, с которого начинается вхождение этой подстроки. Если же подстрока в строке отсутствует, возвращается значение -1.
Сохраним исправленные файлы и запустим приложение на выполнение. Вызовем панель Поиск и попытаемся выполнить поиск. После этого деактивируем данное приложение, переключившись, скажем, на обычный рабочий стол, снова вызовем панель Поиск, выберем в списке приложение ImageViewer и снова попытаемся выполнить поиск.
Заключение
В этой статье рассказывалось о реализации поиска данных в Metro-приложениях. Мы узнали о контракте поиска, изучили соответствующие инструменты программирования и даже добавили в созданное ранее приложение просмотровщика графики возможность поиска файлов по их именам.
Вообще-то, Microsoft рекомендует выводить результатов поиска на отдельной странице, из чего следует, что приложение должно использовать страницы. Однако автор решил не делать этого, поскольку, во-первых, наше приложение очень простое, а во-вторых, чтобы не загромождать код приложения выражениями, выполняющими вывод страниц. В конце концов, эта статья посвящена поиску, а не страницам. (О страницах Metro рассказывалось в одной из предыдущих статей данного цикла.)
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.038 секунд (Общее время SQL: 0.014 секунд - SQL запросов: 51 - Среднее время SQL: 0.00027 секунд))