作为一名技术爱好者,阅读了大量关于Windows 8的技术资料。特别关注到一点,那就是需要保持用户界面的流畅性,因为任何超过30/300毫秒的延迟在触摸系统中都会让人感觉到卡顿。这意味着什么?这意味着需要在需要的地方使用Async/Await来保持代码的异步执行。到目前为止,一切顺利。
现在,让来谈谈搜索魅力。显然在清单文件中启用了这个功能。然后,编写了以下代码,期望它能够正常工作:
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, "");
}
}
}
看起来代码是合理的。但是当运行这段代码时,遇到了一个异常。这真是非常奇怪。
事实证明,这个问题有一个解决方案,但是这个解决方案的文档非常不完整。实际上,它借鉴了很多jQuery的Deferred模式(可以在这里了解更多)。
那么解决方案是什么呢?正如所说,WinRT确实借鉴了jQuery的Deferral / Promise理念。请求一个Deferrable对象,做一些工作,然后完成这个Deferrable对象。
以下是使用WinRT Deferrable对象重构的代码。这种技术可以用于大多数魅力功能。
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
});
// FIXED CODE: Use args.Request.GetDeferral() / deferral.Complete
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();
}
}