📜 ⬆️ ⬇️

Windows 8. Contract "search" in detail

Search inside applications is one of the new, most important and interesting features of Windows 8. Search provides the ability to search not only files and documents on the device, but also allows you to search inside installed applications.

This article covers:
1. Search Metro Search Integration app
2. Contextual hints (suggestions).
3. Processing the request as data is entered.
4. Careless use of a search contract (common integration errors).

1. Search Metro Search Integration app

By default, applications do not support contract searching. This article will look at how you can add a search within the application.
')
The easiest way to add support for a search contract is to use a template in the studio:



VS2012 has a built-in SearchContract template that adds the corresponding entry to the manifest (if this has not been done), adds an entry to app.xaml.cs (redefining the OnSearchActivated method if this has not already been done), and adds a page that accepts the search query with minimal processing logic .

We will not consider in detail the use of this template and will look at adding support for a search contract step by step:

First of all, in the application manifest (Package.appxmanifest file), we need to indicate that our application supports the search contract. To do this, open this manifest in the studio, in the “declarations” tab add a search contract.


Further, in the application class “app.xaml.cs” we can override the algorithm for activating the application through a search contract and specify the logic we need. For simplicity, we’ll make sure that we always open a separate page (SearchPage.xaml) when activated by a search contract.

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(); } 


In this method, we redirect the user to the SearchPage page where the search query is specified as a parameter.

It should be borne in mind that if the application has not been launched, the application is launched via the OnSearchActivated method. Because of this, the current frame may not be created yet. A check for null is performed to initialize the frame when the application is first run.

On the SearchPage page, we can now display the search results by retrieving the search query from the passed parameter:
  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. Contextual hints (suggestions).

The search contract API allows us to add contextual clues when typing a search phrase.
Context-sensitive application hints can only work when the user selects (activates) an application for searching.


2. 1. Text Tips

Adding support is quite simple; in the page constructor we can subscribe to the context-prompt query event.

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


Further, in the SearchPage_SuggestionsRequested method, we can add the necessary contextual hints:

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


Now, if we in the constructor subscribe to the event select query:

SearchPane.GetForCurrentView (). QueryChanged + = SearchPage_QueryChanged;

We will be able to handle the user's choice from the prompts.
  void SearchPage_QueryChanged(SearchPane sender, SearchPaneQueryChangedEventArgs args)        {            SearchByQuery(args.QueryText);        } 


2.2. Complicated tips

The SearchContract API allows us to implement more complex types of contextual cues:




Suppose we have a certain layer of logic (LogicLayer) that returns us a product with fields:
  public class Product    {        public string Name { get; set; }        public string Image { get; set; }        public string Description { get; set; }        public string Id { get; set; }    } 


Now in the SearchPage_SuggestionsRequested method, we need to use the args.Request.SearchSuggestionCollection.AppendResultSuggestion method to add more complex prompts.
  void SearchPage_SuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args)        {            foreach (var product in LogicLayer.SearchProduct(args.QueryText))            {                var image = RandomAccessStreamReference.CreateFromUri(newUri(product.Image));                args.Request.SearchSuggestionCollection.AppendResultSuggestion(product.Name, product.Description, product.Id, image, String.Empty);            }        } 


Here we pass the product Id as tags. When the user selects complex prompts, the QueryChanged event does not fire. To handle complex prompts there is a special
ResultSuggestionChosen event.

We can add to the constructor handling this event.

SearchPane.GetForCurrentView (). ResultSuggestionChosen + = SearchPage_ResultSuggestionChosen;

Now we can get a link to the product ID and process it:
  void SearchPage_ResultSuggestionChosen(SearchPane sender, SearchPaneResultSuggestionChosenEventArgs args)        {            var id = args.Tag;            SearchById(query);        } 

2.3. Contextual prompts on all pages.

In small applications, it is likely that it will be easier to make contextual hints not for each page separately, but for one hint for the entire application.

We can subscribe to search events in the application instance. In this case, since the application can be activated several times, we must be sure that we subscribe only once.

Add the SubscribeToSearchEvents method in 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; } } 



Now it is enough to call it in the OnLaunched and OnSearchActivated methods.

  protected override void OnLaunched(LaunchActivatedEventArgs args) { SubscribeToSearchEvents(); ... } 



  protected override void OnSearchActivated(SearchActivatedEventArgs args) { SubscribeToSearchEvents(); } 



3. Processing the request as data is entered.

If we need to implement even more sophisticated hint scripts, or if we can quickly process the query and immediately show the result of the search query before the completion of the input, we can subscribe to search query change events (QueryChanged).

To do this, we can add the following method to the constructor:

SearchPane.GetForCurrentView (). QueryChanged + = SearchPage_QueryChanged;

Similar to other events, we can process a search query:
  void SearchPage_QueryChanged(SearchPane sender, SearchPaneQueryChangedEventArgs args) { SearchByQuery(args.QueryText); } 



4. Fix typical search integration errors:

The recommendations described here relate to the version of Windows 8 RP and will certainly be corrected in the release. However, there are now several “symptoms” inherent in almost all applications (including built-in system applications, such as People).

4.1. Loss of opportunity to get to the main page.

If the application has not been launched before, the first time you start the application on the search contract, the search page opens. Now if the user goes to the main menu and starts the application again, he will see the search page again and he will not have the opportunity to go to the main menu, since the “back” button appears on the search page only if the application was launched before the search. The only way to get to the main page is only to close the application and restart.

To fix this problem is quite simple. In the method of activating the application by searching (OnSearchActivated) during frame initialization, we will also add an extra transition to the main page.
  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. Numerous instances of the search page

If you enter several search phrases in a row, each time another instance of the page is created, and an attempt to get to the main page using the “back” button causes us to get to the previous search page. Perhaps this is not a bug but a feature, in which case it is necessary to take into account that the search event is triggered in each created instance and processing requests from multiple instances can lead to serious performance problems.
Personally, my opinion is a bug, because quite often I was annoyed by the need to press the “back” button several times to return to the main page.

One solution is quite simple. When activating a search application, check whether the current page is a search page and go back in this case:
  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();        } 


Accordingly, the implementation of the RemoveSearchPage method:
  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(); } } 


Source Code (288,51 kb)

PS Thanks to habraiser Stas Pavlov for valuable comments during the preparation of the article.

Source: https://habr.com/ru/post/146518/


All Articles