As part of something a lot larger that I am currently working on, I wanted to implement the Search charm logic in Windows 8.
Now being the model citizen that I am, I have read all the good technical bumpg around Windows 8, and I paid particular attention to the fact that we really need to keep the UI free, as anything more than 30/300ms (can’t recall which) on a touch system just feels broken.
So what does that mean? Well, it means I have been a good chat and played nice and used Async/Await where needed. All good so far.
So now onto the Search charm. I obviously enabled this in the manifest file. Then I wrote the following code which I expected to work:
sealed partial class App : Application
{
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
....
....
....
....
SetupSearch();
}
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
await SuspensionManager.SaveAsync();
deferral.Complete();
}
private void SetupSearch()
{
var searchPane = SearchPane.GetForCurrentView();
searchPane.SuggestionsRequested += searchPane_SuggestionsRequested;
searchPane.ResultSuggestionChosen += searchPane_ResultSuggestionChosen;
}
void searchPane_ResultSuggestionChosen(SearchPane sender,
SearchPaneResultSuggestionChosenEventArgs args)
{
MessageDialog dialog = new MessageDialog(string.Format("You picked {0}",args.Tag));
dialog.ShowAsync();
}
async void searchPane_SuggestionsRequested(SearchPane sender,
SearchPaneSuggestionsRequestedEventArgs args)
{
var suggestions = Enumerable.Range(1, 2).Select(x => new
{
Desc = string.Format("{0}_{1}", args.QueryText, x.ToString()),
Id = x
});
await Task.Delay(2000);
var imageUri = new Uri("ms-appx:///Assets/search40.png");
var imageSource = Windows.Storage.Streams.
RandomAccessStreamReference.CreateFromUri(imageUri);
args.Request.SearchSuggestionCollection.
AppendSearchSeparator("Demo Suggestions");
foreach (var suggestion in suggestions)
{
args.Request.SearchSuggestionCollection.AppendResultSuggestion(
"Suggestion",
suggestion.Desc,
suggestion.Id.ToString(),
imageSource, "");
}
}
}
That looked fair enough to me. But when I ran this code, I got this Exception:
Most strange.
Turns out this is an issue for which there is a solution, that is just rather poorly documented. In fact, it borrows a lot from the jQuery Deferred pattern (which you can read more about here).
So what is the solution. Well, as I say WinRT has certainly borrowed from the jQuery Deferral / Promise idea. Where we ask for a Deferrable object, do some work, and then complete the Deferrable object.
So here is the code above refactored to use a WinRT Deferrable object. This technique can be used with most of the charms.
sealed partial class App : Application
{
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
....
....
....
....
SetupSearch();
}
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
await SuspensionManager.SaveAsync();
deferral.Complete();
}
private void SetupSearch()
{
var searchPane = SearchPane.GetForCurrentView();
searchPane.SuggestionsRequested += searchPane_SuggestionsRequested;
searchPane.ResultSuggestionChosen += searchPane_ResultSuggestionChosen;
}
void searchPane_ResultSuggestionChosen(SearchPane sender,
SearchPaneResultSuggestionChosenEventArgs args)
{
MessageDialog dialog = new MessageDialog(string.Format("You picked {0}",args.Tag));
dialog.ShowAsync();
}
async void searchPane_SuggestionsRequested(SearchPane sender,
SearchPaneSuggestionsRequestedEventArgs args)
{
var suggestions = Enumerable.Range(1, 2).Select(x => new
{
Desc = string.Format("{0}_{1}", args.QueryText, x.ToString()),
Id = x
});
var deferral = args.Request.GetDeferral();
await Task.Delay(2000);
var imageUri = new Uri("ms-appx:///Assets/search40.png");
var imageSource = Windows.Storage.Streams.
RandomAccessStreamReference.CreateFromUri(imageUri);
args.Request.SearchSuggestionCollection.
AppendSearchSeparator("Demo Suggestions");
foreach (var suggestion in suggestions)
{
args.Request.SearchSuggestionCollection.AppendResultSuggestion(
"Suggestion",
suggestion.Desc,
suggestion.Id.ToString(),
imageSource, "");
}
deferral.Complete();
}
}
As always, here is a small demo project (requires Windows 8 / Visual Studio 2012) : AsyncSearchSuggestionDemo.zip