Adding Search to your C# Metro Style App

Windows 8 introduces Charms and Contracts, which are elegant ways to formalize several trivia tasks in most apps such as search, print, setting, etc. through system-level contracts. For mouse/keyboard user, the search charms can be accessed directly using WinKey + Q.

I do like the standardize idea although this might confuse a new Windows 8 user including me who used to perform those tasks via application UI or menu items.  For example, the Dictionary.com app does not provide obvious action or UI to search for a word. To do that, you would need to use “Search” Charms instead.

image

However, this should not prevent you to add this useful capability in your metro style app. The Dictionary.com app is one of the example.

Note: I use the Windows 8 Release Preview and Visual Studio 2012 RC to create this example.

In this blog post, I create a simple metro style app which list customers in a GridView.  As you can see the list can be big, and it would be painful for our user that would need to scan the list to look for a specific record.

image

Here is the XAML code (MainPage.xaml and MainPage.xaml.cs) that includes DataTemplate and Binding for the GridView. I also hard-coded the ItemsSource assignment in the code behind 🙂 .Nothing is fancy here for anyone who has been working with XAML (e.g., Silverlight, WPF, Windows Phone).

      <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Rectangle Width="120" Height="140" HorizontalAlignment="Left" x:Name="cornerRectangle"/>
            <StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
                <Image Source="Assets/CM-logo.png" Height="50" Margin="0 0 20 0"/>
                <TextBlock Style="{StaticResource HeaderTextStyle}" VerticalAlignment="Center">Customers</TextBlock>
            </StackPanel>
        </Grid>
        <GridView x:Name="gridView" Grid.Row="1" Margin="120 0 0 0" >
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Border Background="Blue" Opacity="0.2"/>
                        <StackPanel Margin="20" Width="200">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding LastName}" Style="{StaticResource TitleTextStyle}"/>
                                <TextBlock xml:space="preserve" Style="{StaticResource TitleTextStyle}">, </TextBlock>                                
                                <TextBlock Text="{Binding FirstName}" Style="{StaticResource TitleTextStyle}" Margin="10 0"/>
                            </StackPanel>
                            <TextBlock Text="{Binding ResidenceState}" Margin="10 0" Style="{StaticResource BodyTextStyle}"/>                        
                        </StackPanel>                    
                    </Grid>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>          

 

protected override void OnNavigatedTo(NavigationEventArgs e)
{
     SamplePeople.BuildSamplePeople();
     gridView.ItemsSource = SamplePeople.People.OrderBy(p => p.LastName).ThenBy(p => p.FirstName).ThenBy(p => p.ResidenceState);
}

Now is the fun part. To enable search capability on my app, I will have to do the followings:

1. Declare the Search Contract in the app manifest. This is pretty straightforward as I just open manifest file and add “search” declaration.  In this blog, I won’t register the app as a search provider because I plan to have user search for customers after they are in my app already.

image

image

2. Add a Search Contract by adding a New Item. It might say that your project misses some dependencies if you start from a blank page project template (the search page requires additional Common files such as LayoutAwarePage and BindableBase). I just click ‘Yes’, and those files will be added automatically.

image

3. Besides the new SearchResult page (SearchResultsPage.xaml), Visual Studio addes OnSearchActivated() handle into the App.xaml.cs automatically. It just makes sure that it will activate the SearchResultPage when the user activates the search charm. In the new SearchResult code-behind page, I implement custom LINQ to get people which contain provided keyword and assign to the Results DefaultViewModel (This seems to be a normal MVVM implementation for most metro style app templates). This example, I allow a user to search by customer’s last or first name and residence state.

protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
     var queryText = navigationParameter as String;

     var filteredPeople = SamplePeople.People
         .Where(p => p.LastName.ToLower().Contains(queryText.ToLower())
                 || p.FirstName.ToLower().Contains(queryText.ToLower())
                 || p.ResidenceState.ToLower().Contains(queryText.ToLower()));

     this.DefaultViewModel["Results"] = filteredPeople.ToList();

     var filterList = new List();
     filterList.Add(new Filter("All", 0, true));

     // Communicate results through the view model
     this.DefaultViewModel["QueryText"] = '\u201c' + queryText + '\u201d';
     this.DefaultViewModel["CanGoBack"] = this._previousContent != null;
     this.DefaultViewModel["Filters"] = filterList;
     this.DefaultViewModel["ShowFilters"] = filterList.Count > 1;
}

 

    public class Person
    {
        public string LastName { get; set; }
        public string FirstName { get; set; }

        public string ResidenceState { get; set; }
    }

    public static class SamplePeople
    {
        #region Last Names
        public static string[] _lastNames = new[]
        {
            "Smith",
            "Johnson",
            "Williams",
            "Jones",
            "Brown",
            "Davis",
            "Miller",
            "Wilson",
            "Moore",
            "Taylor",
            "Anderson",
            "Thomas",
            "Jackson",
            "White",
            "Harris",
            "Martin",
            "Thompson",
            "Garcia",
            "Martinez",
            "Robinson",
            "Clark",
            "Rodriguez",
            "Lewis",
            "Lee",
            "Walker",
            "Hall",
            "Allen",
            "Young",
            "Hernandez",
            "King",
            "Wright",
            "Lopez",
        };
        #endregion

        #region First Names
        public static string[] _firstNames = new[]
        {
            "Jacob",
            "Sophia",
            "Mason",
            "Isabella",
            "William",
            "Emma",
            "Jayden",
            "Olivia",
            "Noah",
            "Ava",
            "Michael",
            "Emily",
            "Ethan",
            "Abigail",
            "Alexander",
            "Madison",
            "Aiden",
            "Mia",
            "Daniel",
            "Chloe",
        };
        #endregion

        #region States
        public static string[] _states = new[]
        {
            "Alabama",
            "Alaska",
            "Arizona",
            "Arkansas",
            "California",
            "Colorado",
            "Connecticut",
            "Delaware",
            "Florida",
            "Georgia",
            "Hawaii",
            "Idaho",
            "Illinois",
            "Indiana",
            "Iowa",
            "Kansas",
            "Kentucky",
            "Louisiana",
            "Maine",
            "Maryland",
            "Massachusetts",
            "Michigan",
            "Minnesota",
            "Mississippi",
            "Missouri",
            "Montana",
            "Nebraska",
            "Nevada",
            "New Hampshire",
            "New Jersey",
            "New Mexico",
            "New York",
            "North Carolina",
            "North Dakota",
            "Ohio",
            "Oklahoma",
            "Oregon",
            "Pennsylvania",
            "Rhode Island",
            "South Carolina",
            "South Dakota",
            "Tennessee",
            "Texas",
            "Utah",
            "Vermont",
            "Virginia",
            "Washington",
            "West Virginia",
            "Wisconsin",
            "Wyoming",
        };
        #endregion

        public static IEnumerable People { get; set; }

        public static void BuildSamplePeople()
        {
            var people = new List<Person>();

            var length = 50;
            Random r = new Random();
            for (int i = 0; i < length; i++)
            {
                var person = new Person();

                person.LastName = _lastNames[r.Next(0, _lastNames.Count())];
                person.FirstName = _firstNames[r.Next(0, _firstNames.Count())];
                person.ResidenceState = _states[r.Next(0, _states.Count())];

                people.Add(person);
            }
            People = people;
        }
    }

This should be all for simple search contract implementation.

image

Here is the XAML code in the searchresult page. I use normal GridView with a template binding properties of each returned person instance.


        <!--             The body of the page in most view states uses an items controls to create multiple radio buttons             for filtering above a horizontal scrolling grid of search results         -->

                <Grid.RowDefinitions>

                    <ItemsControl.ItemsPanel>

                    <ItemsControl.ItemTemplate>

                    <GridView.ItemTemplate>

                                        ,

I could also implement auto-complete, provide more information about filtered list like screenshot below but I will hopefully post those examples later. Enjoy working on your metro style app!

image

Advertisements

4 thoughts on “Adding Search to your C# Metro Style App

  1. Pingback: Join NoSQL movement with RavenDB – Part 2 (Embedded, InMemory, and Management Studio) | Cyan By Fuchsia

  2. Pingback: Adding Auto-suggestion to Metro Style App Search Contract | Cyan By Fuchsia

  3. Pingback: WinRT Settings with Caliburn.Micro | Cyan By Fuchsia

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s