Windows 8 pozwala łatwo integrować wiele swoich funkcjonalności z naszymi aplikacjami. W dzisiejszym odcinku pokażę, jak można skorzystać z mechanizmu wyszukiwania.
Integrację z searchem możemy napisać “od zera” sami (jak choćby w przykładzie MS), możemy wspomóc się też szablonem ‘Search Contract’ jaki oferuje Visual Studio 11. Po wybraniu tego szablonu odpowiednio modyfikowany jest manifest aplikacji, tworzona jest strona do prezentowania wyników wyszukiwania z predefiniowanym kodem oraz dodawany jest kod do klasy obiektu aplikacji (oczywiście w miarę możliwości, jeśli jakaś metoda jest u nas już wcześniej oprogramowana Visual umieści w innym miejscu zakomentowany kod z sugestią, gdzie powinniśmy go docelowo umieścić).
Najważniejsze fragmenty wygenerowanego kodu w utworzonej stronie:
private UIElement _previousContent;
/// <summary>
/// Records the value of the active Window's Content property when the search started.
/// </summary>
public static void Activate(String queryText)
{
// If the Window isn't already using Frame navigation, insert our own Frame
var previousContent = Window.Current.Content;
var frame = previousContent as Frame;
if (frame == null)
{
frame = new Frame();
Window.Current.Content = frame;
}
// Use navigation to display the results, packing both the query text and the previous
// Window content into a single parameter object
frame.Navigate(typeof(SearchVideos),
new Tuple<String, UIElement>(queryText, previousContent));
Window.Current.Activate();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The
/// Parameter property provides the collection of items to be displayed.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// Unpack the two values passed in the parameter object: query text and previous
// Window content
var parameter = (Tuple<String, UIElement>)e.Parameter;
var queryTxt = parameter.Item1;
this._previousContent = parameter.Item2;
// TODO: Application-specific searching logic. The seach process is responsible for
// creating a list of user-selectable result categories:
//
// filterList.Add(new Filter("<filter name>", <result count>));
//
// Only the first filter, typically "All", should pass true as a third argument in
// order to start in an active state. Results for the active filter are provided
// in Filter_SelectionChanged below.
var filterList = new List<Filter>();
filterList.Add(new Filter("All", 0, true));
// Communicate results through the view model
this.DefaultViewModel["QueryText"] = '\u201c' + queryTxt + '\u201d';
this.DefaultViewModel["CanGoBack"] = this._previousContent != null;
this.DefaultViewModel["Filters"] = filterList;
this.DefaultViewModel["ShowFilters"] = filterList.Count > 1;
}
/// <summary>
/// Invoked when the back button is pressed.
/// </summary>
/// <param name="sender">The Button instance representing the back button.</param>
/// <param name="e">Event data describing how the button was clicked.</param>
protected override void GoBack(object sender, RoutedEventArgs e)
{
// Return the application to the state it was in before search results were requested
var frame = this._previousContent as Frame;
if (frame != null)
{
frame.GoBack();
}
else
{
Window.Current.Content = this._previousContent;
}
}
/// <summary>
/// Invoked when a filter is selected using the ComboBox in snapped view state.
/// </summary>
/// <param name="sender">The ComboBox instance.</param>
/// <param name="e">Event data describing how the selected filter was changed.</param>
void Filter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Determine what filter was selected
var selectedFilter = e.AddedItems.FirstOrDefault() as Filter;
if (selectedFilter != null)
{
// Mirror the results into the corresponding Filter object to allow the
// RadioButton representation used when not snapped to reflect the change
selectedFilter.Active = true;
var queryText = (string)this.DefaultViewModel["QueryText"];
Search(queryText); //moja dodana metoda
}
}
/// <summary>
/// Invoked when a filter is selected using a RadioButton when not snapped.
/// </summary>
/// <param name="sender">The selected RadioButton instance.</param>
/// <param name="e">Event data describing how the RadioButton was selected.</param>
void Filter_Checked(object sender, RoutedEventArgs e)
{
// Mirror the change into the CollectionViewSource used by the corresponding ComboBox
// to ensure that the change is reflected when snapped
if (filtersViewSource.View != null)
{
var filter = (sender as FrameworkElement).DataContext;
filtersViewSource.View.MoveCurrentTo(filter);
}
}
Myślę, że szczegółowy kod z komentarzami nie wymaga już komentarza, sam się opisuje. W wygenerowanym kodzie strony jest jeszcze klasa Filter będąca view modelem do obsługi filtrów (u siebie na razie ich nie wykorzystałem).
W klasie App nadpisana zostaje metoda OnSearchActivated (obsługa przypadku aktywacji aplikacji przez samą wyszukiwarkę - pamiętajmy, że z poziomu wyszukiwarki przy tym samym query możemy się szybko przełączać między różnymi aplikacjami)
protected override void OnSearchActivated(Windows.ApplicationModel.Activation.SearchActivatedEventArgs args)
{
MyTube.SearchVideos.Activate(args.QueryText);
}
Zgodnie z sugestią w komentarzu wstawiłem do implementacji metody OnLaunched następujący kawałek kodu:
var searchPane = Windows.ApplicationModel.Search.SearchPane.GetForCurrentView();
searchPane.QuerySubmitted +=
(sender, queryArgs) =>
{
MyTube.SearchVideos.Activate(queryArgs.QueryText);
};
Obiekt klasy SearchPane i obsługa jego zdarzenia QuerySubmitted są - oprócz manifestu - podstawą integracji z wyszukiwarką i można go zobaczyć w każdej prezentacji lub przykładzie, które związane są z tym zagadnieniem.
Po wpisaniu wyrażenia wywoływana jest w końcu moja metoda Search, która - jak ostatnim razem - przy użyciu file query i klasy FileInformationFactory tworzy szybko podgląd przechowywanych plików w danej lokalizacji. Parametr przekazywany przez użytkownika jest tutaj dodatkowym parametrem UserSearchFilter w obiekcie klasy QueryOptions.
void Search(string queryText)
{
var folder = ApplicationData.Current.LocalFolder;
var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;
if (!string.IsNullOrEmpty(queryText))
queryOptions.UserSearchFilter = queryText;
var fileQuery = folder.CreateFileQueryWithOptions(queryOptions);
var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
fileQuery,
Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
95,
Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
false
);
var dataSource = fif.GetVirtualizedFilesVector();
resultsGridView.ItemsSource = dataSource;
}
To nie wszystko, jeśli chodzi o wyszukiwanie. Poprzez obsługę zdarzeń SuggestionsRequested i ResultSuggestionChosen w obiekcie SearchPane możemy uczynić wyszukiwanie jeszcze bardziej przyjemniejszym dostarczając sugestie pytań lub sugerowane wyniki z miniaturkami obrazków oraz odpowiednią obsługę po ich wybraniu. Mamy różne możliwości generowania podpowiedzi - w pamięci, z sieci, z pliku, z systemu Windows. Wspomniane funkcjonalności są dosyć często prezentowane, jak również możemy znaleźć ich opis w dokumentacji.
Brak komentarzy:
Prześlij komentarz