Integrating Search Charm with your Windows 8 Store Application

Posted by: Mahesh Sabnis , on 8/21/2013, in Category Windows Store Apps
Views: 37050
Abstract: A simple demo showing how to integrate your Windows 8 Store App with the Search Charm and pick out a subset of images given the image and some metadata about it.

With the information glut in today’s world, we invariably search for something using a Search engine before looking up any known references. Just like on the web, Search is also an important feature on the desktop. On Windows we have had the search feature for searching files, applications and so on, but they were a little scattered with App search in the Start menu, file search in the Windows Explorer and so on. In Windows 8, the search feature is much more integrated; as a result user can search files, Apps, and the application data very easily. This makes it a great hub for users to start looking for something. The most interesting part of the Search feature is that you can hook your apps into the search mechanism and provide custom search results from your apps well. Today we’ll see how we can hook into the Searching mechanims and leverage the Search charm in our apps.

 

windows-8-charms

Before we get started, lets see how the Search charm works. In the image below, we started searching for the term ‘Ca’:

search-sample

If you carefully observe the screenshot above, by default the matching Apps and Files are displayed. However you will note that there are 76 results for Settings that match the search category and 3K+ Files too. To see the results, just tap/click the Setting or Files listitem. This is the beauty of the Search Charm.

Leveraging Search in our own Apps

Lets say we have a scenario where, you have designed a Site-Seeing Application for tourist places in the country. You want that the end-user should search their desired tourist location and based upon the search, the application should show various site-seeing spots with images and description. To implement this, normally we as a developer can create UI with TextBox (or autocomplete Textbox) and GridView to enter search string and display search results respectively. But for Windows 8 Apps, we can take help of Search Contract to get the job done. So let’s implement it.

Prerequisites

For this application, I have downloaded images for Kanyakumari, Mahabaleshwar, Murudeshwar and Rameshwaram(all tourist places in India) from Google Image search. The copyright to these images belong to the respective owners who shot these images

Building the App

Step 1: Open Visual Studio 2012 and create a new Windows Store App. Name this as ‘Store_CS_Search_Contract’. In this project, in Assets folder create a new subfolder name it as ‘LocationImages’ and put all images in this folder which are downloaded using google image search. In this project add a class file, name it as ‘ModelClasses.cs’ and add the following code in it:

using System.Collections.ObjectModel;

namespace Store_CS_Search_Contract
{
/// <summary>
/// Class to Store Description of the Travel Location
/// </summary>
public class LocationDetails
{
  public string Description { get; set; }
  public string ImageUrl { get; set; }
}

/// <summary>
/// Class contains One to Many detsils of the Travel Location
/// </summary>
public class Location
{
  public int LocationId { get; set; }
  public string LocationName { get; set; }
  public string State { get; set; }
  public ObservableCollection<LocationDetails> Details { get; set; }
}
/// <summary>
/// Class containing Travel Location Details
/// </summary>
public class TravelDetails : ObservableCollection<Location>
{
  public TravelDetails()
  {
   Add(new Location()
   {
    LocationId = 1,
    LocationName = "Mahabaleshwar",
    State="Maharashtra",
    Details = new ObservableCollection<LocationDetails>()
    {
     new LocationDetails() {Description="Elephant
      Rock",ImageUrl="./Assets/LocationImages/Mahb_ElephantRock.jpg"},
     new LocationDetails() {Description="Arthur's
      Chair",ImageUrl="./Assets/LocationImages/Mahb_ArthurChair.jpg"},
     new LocationDetails() {Description="Mahabaleshwar
      Lake",ImageUrl="./Assets/LocationImages/Mahb_Lake.jpg"},
     new LocationDetails() {Description="Pratapgarh",
      ImageUrl="./Assets/LocationImages/Mahb_Pratapgarh.jpg"}
    }
   });
   Add(new Location()
   {
    LocationId = 2,
    LocationName = "Kanyakumari",
    State = "Tamil Nadu",
    Details = new ObservableCollection<LocationDetails>()
    {
     new LocationDetails() {Description="Indian
      Ocean",ImageUrl="./Assets/LocationImages/Kanya_Indian_Ocean.jpg"},
     new LocationDetails() {Description="Sunset
      View",ImageUrl="./Assets/LocationImages/Kanya_Sunset.jpg"},
     new LocationDetails() {Description="Swami Vivekanand Rock
      View",ImageUrl= "./Assets/LocationImages/Kanya_Vivekanand_ROck_1.jpg"},
     new LocationDetails() {Description="Swami Vivekanand Rock
View",ImageUrl="./Assets/LocationImages/Kanya_Vivekanand_ROck_2.jpg"}
    }
   });
   Add(new Location()
{
  LocationId = 3,
  LocationName = "Murudeshwar",
  State="Karnataka",
  Details = new ObservableCollection<LocationDetails>()
  {
   new LocationDetails() {Description="Sea
    Beach",ImageUrl="./Assets/LocationImages/Murud_Beach.jpg"},
   new LocationDetails() {Description="Hotel
    View",ImageUrl="./Assets/LocationImages/Murud_Hotel.jpg"},
   new LocationDetails() {Description="Lord Mahadeva
    Statue",ImageUrl="./Assets/LocationImages/Murud_LordShankar_1.jpg"},
   new LocationDetails() {Description="Lord Magadeva
    Status",ImageUrl="./Assets/LocationImages/Murud_LordShankar_2.jpg"},
   new LocationDetails() {Description="Temple View
    1",ImageUrl="./Assets/LocationImages/Murud_TempleView.jpg"},
   new LocationDetails() {Description="Temple View
    2",ImageUrl="./Assets/LocationImages/Murud_TempleView1.jpg"}
  }
});
Add(new Location()
{
  LocationId = 4,
  LocationName = "Rameshwaram",
  State="Tamil Nadu",
  Details = new ObservableCollection<LocationDetails>()
  {
   new LocationDetails() {
    Description="Sea Beach",
    ImageUrl="./Assets/LocationImages/Ram_Beach.jpg"},
   new LocationDetails() {
    Description="Rameshwaram Temple",
    ImageUrl="./Assets/LocationImages/Ram_Temple_1.jpg"}
  }
});
}

In the above code, the class - Location contains collection of LocationDetails. Both these classes are used to specify the Location information like LocationName, Images and its description etc. The class TravelDetails is used to store information of locations.

Step 2: In this project, add a new Search Contract. This is the predefined ItemTemplate with desired UI for Search Charm.

add-search-contract

 

Once the Search Contract is added in the project, the project will have following files added in Common Folder:

newly-added-files-for-search

Note: StandardStyles.xaml, is already available in the project, new DataTemplates will be added to it for the Search Contract integration piece.

The SearchResultPage is inherited from LayoutAwarePage class. This class defines logic for Navigation Support, Lifetime management and default view model for the Search Page. The class SuspensionManager is used to capture the global session state to deal with process lifecycle management. Additionally there are Converter classes for the additional logic.

The ‘SearchResultPage.xaml’ provides various UI elements e.g. GridView, ListView, Back Button, ItemsControl. The ListView is used for the snapped view. The GridView is used to display search results in full screen mode. The ‘SearchResultPage’ class already contains code for basic logic. The LoadState method is called when the page gets instantiated. The search string entered by the user will be accepted through the navigationParameter.

Filters are provided for the users to work with the result searched. The event implementation Filter_SelectionChanged is already provided in the project. For the current application, we will not be using it.

Step 3: Open SearchResultPage.xaml, and locate GridView named ‘resultsGridView’. This has its ‘ItemsSource’ property set to the ‘resultsViewSource’. The ItemTemplate property is set to the ‘StandardSmallIcon300x70Template’. This is the datatemplate defined in the ‘StandardStyles.xaml’. Open the StandardStyles.xaml and locate the DataTemplate of name ‘StandardSmallIcon300x70Template’ and change it as below:

<DataTemplate x:Key="StandardSmallIcon300x70ItemTemplate">
<Grid Width="1200" Margin="6" Height="600">
  <Grid.ColumnDefinitions>
   <ColumnDefinition Width="180"/>
   <ColumnDefinition Width="*"/>
  </Grid.ColumnDefinitions>
  <Border Background="{StaticResource
   ListViewItemPlaceholderBackgroundThemeBrush}"
   Margin="0,0,0,10"
   Width="40" Height="40">
   <!--<Image Source="{Binding Image}" Stretch="UniformToFill"/>-->
  </Border>
  <StackPanel Grid.Column="1"  Orientation="Vertical" Width="1000">
   <TextBlock Text="{Binding State}" Style="{StaticResource
    BodyTextStyle}"
    TextWrapping="NoWrap" Width="100"/>
    <ListBox Height="600" Width="800"
     ItemsSource="{Binding Details}">
     <ListBox.ItemTemplate>
      <DataTemplate>
       <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Description}" Width="100"
         TextWrapping="Wrap" Foreground="Red"></TextBlock>
        <Image Source="{Binding ImageUrl}" Stretch="UniformToFill"
         Height="100" Width="100"></Image>
       </StackPanel>
      </DataTemplate>
     </ListBox.ItemTemplate>
    </ListBox>
   </StackPanel>
  </Grid>
</DataTemplate>

Note: The Image inside Border is commented. This DataTemplate contains Grid and in the first column of the Grid, the StackPanel is defined which contains TextBlock bind with the ‘State’ property defined in the ‘Location’ class. The StackPanel also contains ListBox which is used to show Description and Location Image using ImageUrl property.

Step 4: In the SearchResultPage.caml change the resultsGridView GridView with ItemContainerStyle as below:

<GridView.ItemContainerStyle>
<Style TargetType="Control">
  <Setter Property="Height" Value="600"/>
  <Setter Property="Width" Value="1200"/>
  <Setter Property="Margin" Value="0,0,38,8"/>
</Style>
</GridView.ItemContainerStyle>

Step 5: Change the implementation of the LoadState method from SearchResultsPage class as below:

/// <summary>
/// Populates the page with content passed during navigation. 
/// Any saved state is also
/// provided when recreating a page from a prior session.
/// </summary>
/// <param name="navigationParameter">The parameter value passed to
/// <see cref="Frame.Navigate(Type, Object)"/> when this page was
/// initially requested.
/// </param>
/// <param name="pageState">A dictionary of state preserved by this page
/// during an earlier
/// session.  This will be null the first time a page is visited.</param>
protected override void LoadState(Object navigationParameter,
Dictionary<String, Object> pageState)
{
if (navigationParameter as String == "")
{
  VisualStateManager.GoToState(this, "Sorry No Results Found", true);
}
else
{
  var queryText = navigationParameter as String;
  this.DefaultViewModel["QueryText"] = '\u201c' + queryText + '\u201d';
  //My Logic Starts Here Search for the location details from
  //TrevelDetails class.
  IEnumerable<Location> locations = from loc in new TravelDetails()
   where loc.LocationName.ToLower().Contains(queryText.ToLower())
   select loc;
  //assign the locations to the Results
  this.DefaultViewModel["Results"] = locations;
  //If the search returns more than 0 results
  if (locations.Count() > 0)
  {
   VisualStateManager.GoToState(this, locations.Count().ToString() + "
    Results Found", true);
  }
  //else display apprpriate message
  else
  {
   VisualStateManager.GoToState(this, "Sorry No Results Found", true);
  }
}
//Ends Here
}

The above code defines application specific logic. The queryText has the search string entered by the end-user in the search charm. Based upon this string, the information about the location will be extracted from the TravelDetails class. This data is now assigned to the DefaultViewModel. This is an observable map defined in the LayoutAwarePage class and this is used to contains dynamically changed data values and notify to the UI.

Step 6: Open MainPage.xaml and add the TextBloxk on it:

<TextBlock HorizontalAlignment="Left" Height="692" Margin="206,46,0,0"
                   TextWrapping="Wrap"
                   Text="Take the Mouse Cursor to the top right, the Charm Contract will be displayed. Select the Search, you will get the Search Contract."
                   FontFamily="Segoe UI" FontSize="80"
                   VerticalAlignment="Top"
                   Width="1084"/>

Step 7: Run the Application, initially you will get the following results:

final-outcome-1

Follow the instructions given above. Once you move mouse to the top left and select search, you will get UI as below:

final-outcome-2

Enter the Search string in the TextBox and press enter, you will get the result as below:

final-outcome-3

Here, you will get all locations in Kanyakumari, India (a popular tourist destination).

Conclusion

That was an unconventional but effective Demo of how to use the Search charm in our own custom Windows 8 Store Apps. Essentially if it were a full fledged photo-viewer app with thousands of photos, the search functionality would nicely compliment it by picking out the relevant photos. Now that we know how to hook into the search charm we can very easily extend it and return relevant search results.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Mahesh Sabnis is a DotNetCurry author and Microsoft MVP having over 17 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). Follow him on twitter @maheshdotnet


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!

Categories

JOIN OUR COMMUNITY

POPULAR ARTICLES

FREE .NET MAGAZINES

Free DNC .NET Magazine

Tags

JQUERY COOKBOOK

jQuery CookBook