Статьи по теме
Вам понадобится

Для разработки под Windows вам понадобиться следующее ПО:

Пробная версия Windows 10

Попробуйте новейшую версию ОС.

Visual Studio

Visual Studio — это интегрированная среда разработки с широкими возможностями для создания потрясающих приложений для Windows, Android и iOS, а также современных веб-приложений и облачных служб.

Microsoft .NET Framework 4.6

Пакет многоплатформенного нацеливания .NET Framework 4.6 позволяет разработчикам создавать приложения для .NET Framework 4.6, используя Visual Studio или сторонние IDE.

Windows 8. Контракт «поиск» в деталях

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

В этой статье рассматривается:
1. Интеграция поиска в метро приложение
2. Контекстные подсказки (suggestions).
3. Обработка запроса по мере ввода данных.
4. Неосторожное использование контракта поиска (обычные ошибки интеграции).

1. Интеграция поиска в метро приложение

По умолчанию приложения не поддерживают контракт поиска. В этой статье рассмотрим, как можно добавить поиск внутри приложения.

Самым простым способом добавления поддержки контракта поиска является использование готового шаблона в студии:

В VS2012 есть встроенный шаблон SearchContract который добавляет соответствующую запись в манифест (если этого не было сделано), добавляет запись в app.xaml.cs(переопределение метода OnSearchActivated если этого еще не было сделано), и добавляет страницу принимающий поисковой запрос с минимальной логикой обработки.

Мы не будем детально рассматривать использования этого шаблона и пошагово рассмотрим добавление поддержки контракта поиска:

В первую очередь в манифесте приложения (файл Package.appxmanifest) нам необходимо указать, что наше приложение поддерживает контракт поиска. Для этого открыв этот манифест в студии, во вкладке “declarations” добавляем контракт поиска.

Далее в классе приложения “app.xaml.cs” мы можем переопределить алгоритм активации приложения через контракт поиска и указать нужную нам логику. Для простоты сделаем, что бы у нас всегда открывалась отдельная страница (SearchPage.xaml) при активации по контракту поиска.

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

В этой статье рассматривается:
1. Интеграция поиска в метро приложение
2. Контекстные подсказки (suggestions).
3. Обработка запроса по мере ввода данных.
4. Неосторожное использование контракта поиска (обычные ошибки интеграции).

1. Интеграция поиска в метро приложение

По умолчанию приложения не поддерживают контракт поиска. В этой статье рассмотрим, как можно добавить поиск внутри приложения.

Самым простым способом добавления поддержки контракта поиска является использование готового шаблона в студии:

В VS2012 есть встроенный шаблон SearchContract который добавляет соответствующую запись в манифест (если этого не было сделано), добавляет запись в app.xaml.cs(переопределение метода OnSearchActivated если этого еще не было сделано), и добавляет страницу принимающий поисковой запрос с минимальной логикой обработки.

Мы не будем детально рассматривать использования этого шаблона и пошагово рассмотрим добавление поддержки контракта поиска:

В первую очередь в манифесте приложения (файл Package.appxmanifest) нам необходимо указать, что наше приложение поддерживает контракт поиска. Для этого открыв этот манифест в студии, во вкладке “declarations” добавляем контракт поиска.

Далее в классе приложения “app.xaml.cs” мы можем переопределить алгоритм активации приложения через контракт поиска и указать нужную нам логику. Для простоты сделаем, что бы у нас всегда открывалась отдельная страница (SearchPage.xaml) при активации по контракту поиска.

protected override void OnSearchActivated
(SearchActivatedEventArgs args)
 {
 var frame = Window.Current.Content as Frame;
 if(frame==null)
    {
    frame=new Frame();
 Window.Current.Content = frame;
    }
          
 frame.Navigate(typeof(SearchPage), args.QueryText);
 Window.Current.Activate();
        }

В этом методе мы перенаправляем пользователя на страницу SearchPage где в качестве параметра указан поисковой запрос.

Надо учитывать, что если приложение не было запущено, приложение запускается через метод OnSearchActivated. В связи с этим текущий фрейм может быть еще не создан. Проверка на null осуществляется для инициализации фрейма при первом запуске приложения.

На странице SearchPage теперь мы можем отобразить результаты поиска, получив поисковой запрос из переданного параметра:

protected override void OnNavigatedTo(NavigationEventArgs e)
 {
 var query = (string)e.Parameter;
  SearchByQuery(query);
  }

 private void SearchByQuery(string queryText)
  {
 pageTitle.Text = "Search result for \"" + queryText + "\":";
  //Логика обработки поискового запроса
    }

2. Контекстные подсказки (suggestions).

API контракта поиска позволяет нам добавлять контекстные подсказки при наборе поисковой фразы.
 Контекстные подсказки приложения могут работать только тогда, когда пользователь выберет (активирует) приложение для поиска.

2. 1. Текстовые подсказки

Добавить поддержку довольно просто, в конструкторе страницы мы можем подписаться на событие запроса контекстных подсказок.

public SearchPage()
{
this.InitializeComponent();
 SearchPane.GetForCurrentView().
  SuggestionsRequested 
  += SearchPage_SuggestionsRequested;
}

Далее в методе SearchPage_SuggestionsRequested мы можем добавить необходимые контекстные подсказки:

void SearchPage_SuggestionsRequested
(SearchPane sender, SearchPaneSuggestions
RequestedEventArgs args)
 {
var products=new[] { "apple", "cheese", 
"bread", "onion", "orange", "potato"}
  args.Request.SearchSuggestionCollection.
  AppendQuerySuggestions(products);
 }

Теперь, если мы в конструкторе подпишемся на событие выбор запроса:

        SearchPane.GetForCurrentView().QueryChanged += SearchPage_QueryChanged;

Мы сможем обрабатывать выбор пользователя из подсказок.

void SearchPage_QueryChanged
(SearchPane sender, SearchPaneQueryChanged
EventArgs args)
  {
  SearchByQuery(args.QueryText);
 }

2.2. Сложные подсказки

API SearchContract позволяет нам реализовать более сложные виды контекстных подсказок:

Предположим у нас есть некий слой логики (LogicLayer) который возвращает нам продукт с полями:

public class Product
    {
  public string Name { get; set; }
  public string Image { get; set; }
public string Description { get; set; }
 public string Id { get; set; }
    }

Теперь в методе SearchPage_SuggestionsRequested мы должны использовать метод args.Request.SearchSuggestionCollection.AppendResultSuggestion для добавления более сложных подсказок.

void SearchPage_SuggestionsRequested
(SearchPane sender, SearchPaneSuggestions
RequestedEventArgs args)
  {
  foreach (var product in LogicLayer.Search
 Product(args.QueryText))
  {
var image = RandomAccessStreamReference.
CreateFromUri(newUri(product.Image));
args.Request.SearchSuggestionCollection.
AppendResultSuggestion
 (product.Name, product.Description, product.Id,
 image, String.Empty);
 }
        }

Здесь мы в качестве тегов передаем Id продукта. При выборе пользователем сложных подсказок не срабатывает событие QueryChanged. Для обработки сложных подсказок есть специальное 
событие ResultSuggestionChosen.

Мы можем добавить в конструктор обработку этого события.

        SearchPane.GetForCurrentView().ResultSuggestionChosen += SearchPage_ResultSuggestionChosen;

Теперь мы можем получить ссылку на идентификатор продукта и обработать его:

void SearchPage_ResultSuggestionChosen
(SearchPane sender, SearchPaneResultSuggestion
ChosenEventArgs args)
  {
 var id = args.Tag;
  SearchById(query);
  }

2.3. Контекстные подсказки на всех страницах.
 
В небольших приложениях скорее всего будет проще сделать контекстные подсказки не отдельно для каждой страницы,  а одну подсказку для всего приложения.
 
Мы можем подписаться на события поиска в экземпляре приложения. При этом, так как приложение может быть активировано несколько раз, мы должны быть уверены что подпишемся только один раз.
 
Добавим метод SubscribeToSearchEvents в App.xaml.cs 

private bool isSubscribed;
 public void SubscribeToSearchEvents()
{
 if (!isSubscribed)
   {
    isSubscribed = true;
   SearchPane.GetForCurrentView().SuggestionsRequested
   += SearchPage_SuggestionsRequested;
     SearchPane.GetForCurrentView().ResultSuggestionChosen 
    += SearchPage_ResultSuggestionChosen;
   SearchPane.GetForCurrentView().QueryChanged
      += SearchPage_QueryChanged; 
            }
        }

Теперь достаточно вызвать его в методах OnLaunched и OnSearchActivated

protected override void OnLaunched(Launch
ActivatedEventArgs args)
        {
            SubscribeToSearchEvents();
            ...
         }
protected override void OnSearchActivated
(SearchActivatedEventArgs args)
        {
            SubscribeToSearchEvents();
        }

3. Обработка запроса по мере ввода данных.

Если нам требуется реализовать еще более сложные сценарии подсказок, или если мы можем быстро обработать запрос и сразу показать результат поискового запроса до завершения ввода, мы можем подписаться на события изменения поискового запроса (QueryChanged).

Для этого можем добавить в конструктор следующий метод:

SearchPane.GetForCurrentView().QueryChanged += SearchPage_QueryChanged;

Аналогично остальным событиям мы можем обработать поисковый запрос:

void SearchPage_QueryChanged
(SearchPane sender, SearchPaneQuery
ChangedEventArgs args)
      {
               SearchByQuery(args.QueryText);
      }

4. Исправляем типичные ошибки интеграции поиска:

Описанные здесь рекомендации относиться к версии Windows 8 RP и наверняка будут исправлены в релизе. Тем не менее сейчас есть несколько «симптом» присущих практически всем приложениям (включая встроенные системные приложения, такие как «Люди»).

4.1. Потеря возможности попасть на главную страницу.

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

Исправить эту проблему достаточно просто. В методе активации приложения по поиску (OnSearchActivated) при инициализации фрейма мы также добавим лишний переход на главную страницу.

protected override void OnSearchActivated
(SearchActivatedEventArgs args)
        {
            var frame = Window.Current.Content as Frame;
            if(frame==null)
            {
                frame=new Frame();
                Window.Current.Content = frame;
//Переход на главную страницу
                frame.Navigate(typeof(MainPage));
            }           
            frame.Navigate(typeof(SearchPage), args.QueryText);
            Window.Current.Activate();
        }

4.2. Многочисленные экземпляры страницы поиска

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

Лично мое мнение это баг, так как довольно часто меня раздражала небходимость по несколько раз нажимать кнопку «назад» что бы снова вернуться на главную страницу.

Одно из решений довольно простое. При активации приложения по поиску проверять, является ли текущая страница страницей поиска и возвращаться назад в таком случае:

protected override void OnSearchActivated
(SearchActivatedEventArgs args)
  {
 RemoveSearchPage();
var frame = Window.Current.Content as Frame;
 if(frame==null)
{
  frame=new Frame();
Window.Current.Content = frame;
 frame.Navigate(typeof(MainPage));
}
            
frame.Navigate(typeof(SearchPage), args.QueryText);
 Window.Current.Activate();
 }

Соответственно реализация метода RemoveSearchPage:

private void RemoveSearchPage()
 {
 var frame = Window.Current.Content as Frame;
 if (frame== null)
 {
 return;
 }
                        
 var page=frame.Content as Page;
 if (page == null)
 {
 return;
}

if (page.GetType()==typeof(SearchPage))
  {
 frame.GoBack();
 }
  }

Исходный код (288,51 kb)

P.S. Спасибо хабраюзеру  Стасу Павлову за ценные замечания при подготовке статьи.

Автор статьи: Ахмед Шериев.

 

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