Search (filtering results based on queryText)
-
Sunday, April 08, 2012 4:20 AM
I'm implementing the Search Contract in XAML and C#. Other forum threads point to the Search sample, but it doesn't answer my question. Also watched the Build talk on search, but that example uses Javascript.
So far the search activates fine, the SearchResults page displays a list of the required dataset (coming from a RSS feed).
The problem: The results aren't being filtered based on the queryText.
Below is the code from the Filter_SelectionChanged event in SearchResults.cs
FeedDataSource _feedDataSource = App.DataSource; var Results = (_feedDataSource.Feeds[0]).Items; this.DefaultViewModel["Results"] = Results;
Happy to provide more info if that helps.
techAU http://techAU.tv
All Replies
-
Sunday, April 08, 2012 4:37 AMI'm also looking into how to do search, basically, to search files within a folder. So the answer to your question would also be a good help to me also.
James
-
Sunday, April 08, 2012 7:56 AM
you need to explain a bit more, anyway I'll post how I handle the search:
SearchPage.xaml:
private SearchPane _searchPane; private string _lastQuery; public SearchPage() { this.InitializeComponent(); _searchPane = SearchPane.GetForCurrentView(); _searchPane.QuerySubmitted += OnsearchPane_QuerySubmitted; this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled; } protected override void OnNavigatedTo(NavigationEventArgs e) { var query = e.Parameter as string; if (!String.IsNullOrWhiteSpace(query)) DoSearch(query); } private void OnsearchPane_QuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args) { if (!String.IsNullOrWhiteSpace(args.QueryText)) DoSearch(args.QueryText); }
-Soroush
- Edited by Soroush Mirzaei Sunday, April 08, 2012 7:57 AM
-
Sunday, April 08, 2012 12:08 PM
Happy to provide more information.. what do you need to know ?
Here's my current SearchResults.xaml.cs code..
using techAU8.Data; using System; using System.Collections.Generic; using System.IO; using System.Linq; using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Search; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // The Search Contract item template is documented at http://go.microsoft.com/fwlink/?LinkId=234240 namespace techAU8 { public sealed partial class SearchResultsPage : techAU8.Common.LayoutAwarePage { private UIElement _previousContent; public SearchResultsPage() { this.InitializeComponent(); } 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(SearchResultsPage), new Tuple<String, UIElement>(QueryText, previousContent)); Window.Current.Activate(); } 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 queryText = parameter.Item1; this._previousContent = parameter.Item2; var filterList = new List<Filter>(); filterList.Add(new Filter("Results", 5, true)); filterList.Add(new Filter("Latest News", 0, false)); //set number to the amount of results filterList.Add(new Filter("Reviews", 0, false)); //set number to the amount of results filterList.Add(new Filter("Podcast", 0, false)); //set number to the amount of results // 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; } 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; } } public class SearchResult { public string Title { get; set; } public string Subtitle { get; set; } public object Image { get; set; } } 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; //Reference the first RSS feed in the feedData.cs file, bind to first Grid - Lastest News. FeedDataSource _feedDataSource = App.DataSource; var Results = (_feedDataSource.Feeds[0]).Items; this.DefaultViewModel["Results"] = Results; } } 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); } } private sealed class Filter : techAU8.Common.BindableBase { private String _name; private int _count; private bool _active; public Filter(String name, int count, bool active = false) { this.Name = name; this.Count = count; this.Active = active; } public override String ToString() { return Description; } public String Name { get { return _name; } set { if (this.SetProperty(ref _name, value)) this.OnPropertyChanged("Description"); } } public int Count { get { return _count; } set { if (this.SetProperty(ref _count, value)) this.OnPropertyChanged("Description"); } } public bool Active { get { return _active; } set { this.SetProperty(ref _active, value); } } public String Description { get { return String.Format("{0} ({1})", _name, _count); } } public string winsearch { get; set; } } } }techAU http://techAU.tv
-
Sunday, April 08, 2012 1:37 PM
I briefly scanned through your code, do you get the query text when you navigate to the page? (var queryText = parameter.Item1;) Because if you do, then your search implementation is fine.
Also I noticed you are not listening to QuerySubmitted event.
-Soroush
-
Sunday, April 08, 2012 2:33 PM
I've tried experimenting with your OnsearchPane_QuerySubmitted code above, but can't get it to work.
If you could help integrate that into my code, that would be awesome, or at least point me to what I should be looking for.
The Feeddata is placed in the Filter section and works, so I had assumed that was enough, but the results need to be filtered only if the title of an item matches the Querytext submitted by the user.
techAU http://techAU.tv
-
Sunday, April 08, 2012 3:09 PM
The code that I've posted should pretty much do it, set a breakpoint in the QuerySubmitted event handler, then go to your search page, bring up the search charm do a search and see if the event gets fired, I think I used the search sample to create this.
-Soroush
-
Sunday, April 08, 2012 3:17 PM
You should come up with something like this:
public sealed partial class SearchResultsPage : techAU8.Common.LayoutAwarePage { private UIElement _previousContent; private readonly SearchPane _searchPane; public SearchResultsPage() { this.InitializeComponent(); _searchPane = SearchPane.GetForCurrentView(); _searchPane.QuerySubmitted += _searchPane_QuerySubmitted; } private void _searchPane_QuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args) { if (!String.IsNullOrEmpty(args.QueryText)) YourFilteringLogic(args.QueryText); } private void YourFilteringLogic(string searchQuery) { //Create your filter logic here } }-Soroush
-
Sunday, April 08, 2012 11:05 PM
Yep, its the
//Create your filter logic here
that's the problem. If I have a GridView full of results, what is the syntax for filtering those items. Clearly I need to compare the QueryText to items, just not sure how to loop through each item in the Results.
Right now this returns 10 items
var Results = (_feedDataSource.Feeds[0]).Items;
techAU http://techAU.tv
-
Monday, April 09, 2012 5:59 AM
Ok great so your search works.
I'm not sure how your collection looks like, but you can simply create a LINQ expression to filter it. like this:
var filteredResult = from i in myCollection where i.Contains(searchQuery) select i;
-Soroush
- Edited by Soroush Mirzaei Monday, April 09, 2012 1:20 PM
- Marked As Answer by techAU Wednesday, April 11, 2012 9:44 AM
-
Tuesday, April 10, 2012 2:28 PM
Ok I am so close now.. here's the code I've implemented..
private void Filter_SelectionChanged(object sender, SelectionChangedEventArgs e) { var selectedFilter = e.AddedItems.FirstOrDefault() as Filter; if (selectedFilter != null) { selectedFilter.Active = true; FeedDataSource _feedDataSource = App.DataSource; var theQuery = "Windows"; var Results = (_feedDataSource.Feeds[0]).Items; var filteredResult = from i in Results where i.Title.Contains(theQuery) select i; this.DefaultViewModel["Results"] = filteredResult; } }You can see I'm using the string Windows.. whatever I change it to does filter the GridView items based on that term. The final piece of the puzzle is getting access to the queryText.
As you can see, I'm currently inside the Filter_SelectionChanged event handler, but queryText just returns nothing (""). How can I access the QueryText from the OnNavigatedTo event?
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 queryText = parameter.Item1; this._previousContent = parameter.Item2;If I can work that out, problem will be 100% complete and we'll have a working C# code implementation from a GridView populated with RSS content.techAU http://techAU.tv
- Marked As Answer by techAU Wednesday, April 11, 2012 9:44 AM
-
Tuesday, April 10, 2012 2:59 PM
If you navigate from another page to this one, you need to pass the query text along, you can get the query text like I showed, in the QuerySubmitted event.
If your app gets activated from the search charm (which probably will), that's easy to handle too:
override the OnSearchActivated in the app.xaml, get the query, then navigate to your search page, like this:
protected override void OnSearchActivated(SearchActivatedEventArgs args) { base.OnSearchActivated(args); _rootFrame.Navigate(typeof(Views.SearchPage), args.QueryText); Window.Current.Content = _rootFrame; Window.Current.Activate(); }
-Soroush
- Edited by Soroush Mirzaei Tuesday, April 10, 2012 7:53 PM
-
Tuesday, April 10, 2012 9:35 PM
Great news! Search is now working! Well there is still one bug.
The search initially returns the full dataset in the GridView, but if you press search again, it then correctly filters the results based on the queryText.
I suspect its the _searchPane = SearchPane.GetForCurrentView(); line. Should I be setting this somewhere ?
REALLY appreciate all of your time and help Soroush, it's been awesome.. almost there.
techAU http://techAU.tv
-
Tuesday, April 10, 2012 9:38 PM
Forget that.. Just fixed it !
I put that code in the OnSearchActivated override and it works.
Seriously mate, can't thank you enough for all your help.
techAU http://techAU.tv
-
Wednesday, April 11, 2012 4:59 AM
You're welcome :) I'm glad I could help!
-Soroush


