重新想象 Windows 8 Store Apps (38) - 契约: Search Contract
作者:webabcd
介绍
重新想象 Windows 8 Store Apps 之 契约
- Search Contract - 右侧边栏称之为 Charm, 其中的“搜索”称之为 Search Contract
- 使用 Search Contract 的搜索建议,数据源在本地,以及从输入法编辑器中获取相关信息
- 使用 Search Contract 的搜索建议,数据源在服务端,以及为搜索建议增加图标、描述等
- 使用 Search Contract 的基于本地文件的搜索建议,数据来源于文件的 metadata
示例
1、演示 Search Contract 的基本应用
Contracts/SearchContract/Demo.xaml
<Page x:Class="XamlDemo.Contracts.SearchContract.Demo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Contracts.SearchContract" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" Text="直接通过键盘输入即可激活 SearchPane" /> <Button Name="btnShowSearch" Content="打开 SearchPane" Click="btnShowSearch_Click_1" Margin="0 10 0 0" /> </StackPanel> </Grid> </Page>
Contracts/SearchContract/Demo.xaml.cs
/* * 本例演示 Search Contract 的基本应用 * * Search Contract - 右侧边栏称之为 Charm,其中的“搜索”称之为 Search Contract * * 1、在 Package.appxmanifest 中新增一个“搜索”声明 * 2、在 App.xaml.cs 中 override void OnSearchActivated(SearchActivatedEventArgs args),如果 app 是由搜索激活的,则可以在此获取相关的搜索信息 * * SearchActivatedEventArgs - 当 app 由搜索激活时的事件参数 * QueryText - 搜索文本 * PreviousExecutionState - 此 app 被搜索激活前的执行状态(ApplicationExecutionState 枚举:NotRunning, Running, Suspended, Terminated, ClosedByUser) * SplashScreen - 启动画面对象 * * SearchPane - 搜索面板 * GetForCurrentView() - 获取当前的 SearchPane * Show() - 显示搜索面板,需要的话可以指定初始查询字符串 * PlaceholderText - 当搜索框没有输入焦点且用户未输入任何字符时,搜索框中的提示文本 * SearchHistoryEnabled - 是否启用搜索建议的历史记录功能,默认值是 true * SearchHistoryContext - 如果启用了搜索建议的历史记录功能,则此值用于指定历史纪录的上下文,即历史记录会在此上下文中保存和获取,也就是说一个 app 的搜索建议历史记录可以有多套 * ShowOnKeyboardInput - 如果发现键盘输入,是否激活搜索面板,默认值是 false * Visible - 搜索面板是否是打开状态,只读 * QueryChanged - 搜索面板的搜索框中的文本发生变化时所触发的事件 * QuerySubmitted - 提交搜索面板的搜索框中的文本时所触发的事件 * VisibilityChanged - 打开或关闭搜索面板时所触发的事件 */ using System; using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Search; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Contracts.SearchContract { public sealed partial class Demo : Page { private SearchPane _searchPane; public Demo() { this.InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 获取当前的 SearchPane,并注册相关事件 _searchPane = SearchPane.GetForCurrentView(); _searchPane.QueryChanged += _searchPane_QueryChanged; _searchPane.QuerySubmitted += _searchPane_QuerySubmitted; // 当搜索框没有输入焦点且用户未输入任何字符时,搜索框中的提示文本 _searchPane.PlaceholderText = "请输入"; // 是否启用搜索建议的历史记录 _searchPane.SearchHistoryEnabled = true; // 指定搜索建议的历史记录的上下文 _searchPane.SearchHistoryContext = "abc"; // 如果有键盘输入,则直接激活 SearchPane _searchPane.ShowOnKeyboardInput = true; // 通过搜索激活应用程序时(参见 App.xaml.cs 中的 OnSearchActivated() 方法) SearchActivatedEventArgs searchActivated = (SearchActivatedEventArgs)e.Parameter; if (searchActivated != null) ShowSearchPane(searchActivated.QueryText); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 取消相关事件的监听 _searchPane.QueryChanged -= _searchPane_QueryChanged; _searchPane.QuerySubmitted -= _searchPane_QuerySubmitted; _searchPane.ShowOnKeyboardInput = false; } private void btnShowSearch_Click_1(object sender, RoutedEventArgs e) { ShowSearchPane(); } // 显示 Search 面板 private void ShowSearchPane(string queryText="") { _searchPane.Show(queryText); lblMsg.Text = queryText; } void _searchPane_QueryChanged(SearchPane sender, SearchPaneQueryChangedEventArgs args) { lblMsg.Text = args.QueryText; } void _searchPane_QuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args) { lblMsg.Text = args.QueryText; } } }
App.xaml.cs
// 通过搜索激活应用程序时所调用的方法 protected override void OnSearchActivated(SearchActivatedEventArgs args) { if (args.PreviousExecutionState == ApplicationExecutionState.Running) return; var rootFrame = new Frame(); rootFrame.Navigate(typeof(MainPage), args); Window.Current.Content = rootFrame; Window.Current.Activate(); }
2、本例演示如何使用 Search Contract 的搜索建议,数据源在本地。同时演示如何从输入法编辑器中获取相关信息
Contracts/SearchContract/LocalSuggestion.xaml
<Page x:Class="XamlDemo.Contracts.SearchContract.LocalSuggestion" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Contracts.SearchContract" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" Text="本例演示如何使用 Search Contract 的搜索建议,数据源在本地。同时演示如何从输入法编辑器中获取相关信息" /> </StackPanel> </Grid> </Page>
Contracts/SearchContract/LocalSuggestion.xaml.cs
/* * 本例演示如何使用 Search Contract 的搜索建议,数据源在本地。同时演示如何从输入法编辑器中获取相关信息 * * SearchPane - 搜索面板 * SuggestionsRequested - 用户的查询文本发生改变,app 需要提供新的建议时所触发的事件(事件参数 SearchPaneSuggestionsRequestedEventArgs) * QuerySubmitted - 提交搜索面板的搜索框中的文本时所触发的事件 * * SearchPaneSuggestionsRequestedEventArgs - 当需要提供新的建议时所触发的事件 * QueryText - 搜索文本 * Request - 关于建议信息的对象,返回 SearchPaneSuggestionsRequest 类型的数据 * SearchPaneQueryLinguisticDetails - 关于输入法编辑器信息(IME)的对象,返回 SearchPaneQueryLinguisticDetails 类型的数据 * * SearchPaneSuggestionsRequest - 关于建议信息的对象 * SearchSuggestionCollection - 搜索面板的搜索建议集合 * Size - 搜索建议的数量,最多只支持 5 个元素,就算超过 5 个系统也只会显示前 5 个 * AppendQuerySuggestion() & AppendQuerySuggestions() - 将指定的建议信息添加到搜索面板的建议集合中 * * SearchPaneQueryLinguisticDetails - 关于输入法编辑器(IME - Input Method Editor)信息的对象 * QueryTextAlternatives - 当前查询文本 IME 中的全部可能的文本列表 * QueryTextCompositionLength - 当前在 IME 中输入的查询文本的长度 * QueryTextCompositionStart - 当前在 IME 中输入的查询文本在整个查询字符串中的起始位置 */ using System; using Windows.ApplicationModel.Search; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Contracts.SearchContract { public sealed partial class LocalSuggestion : Page { private SearchPane _searchPane; private static readonly string[] suggestionList = { "beijing", "北京", "beiji", "北极", "shanghai", "上海", "tianjin", "天津", "chongqing", "重庆" }; public LocalSuggestion() { this.InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 获取当前的 SearchPane,并注册相关事件 _searchPane = SearchPane.GetForCurrentView(); _searchPane.SuggestionsRequested += _searchPane_SuggestionsRequested; _searchPane.QuerySubmitted += _searchPane_QuerySubmitted; } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 取消相关事件的监听 _searchPane.SuggestionsRequested -= _searchPane_SuggestionsRequested; _searchPane.QuerySubmitted -= _searchPane_QuerySubmitted; } void _searchPane_SuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args) { if (!string.IsNullOrEmpty(args.QueryText)) { // 根据用户当前的输入法编辑器中的内容,在建议列表中显示相关建议 foreach (string alternative in args.LinguisticDetails.QueryTextAlternatives) { foreach (string suggestion in suggestionList) { if (suggestion.StartsWith(alternative, StringComparison.CurrentCultureIgnoreCase)) { args.Request.SearchSuggestionCollection.AppendQuerySuggestion(suggestion); // 建议列表最多只支持 5 个元素,超过 5 个也只会显示前 5 个 if (args.Request.SearchSuggestionCollection.Size >= 5) break; } } } // 根据用户的当前输入,在建议列表中显示相关建议(不考虑输入法编辑器中的内容) foreach (string suggestion in suggestionList) { if (suggestion.StartsWith(args.QueryText, StringComparison.CurrentCultureIgnoreCase)) { args.Request.SearchSuggestionCollection.AppendQuerySuggestion(suggestion); // 建议列表最多只支持 5 个元素,超过 5 个也只会显示前 5 个 if (args.Request.SearchSuggestionCollection.Size >= 5) break; } } } } void _searchPane_QuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args) { lblMsg.Text = args.QueryText; } } }
3、本例演示如何使用 Search Contract 的搜索建议,数据源在服务端。同时演示如何为搜索建议增加图标、描述等
Contracts/SearchContract/RemoteSuggestion.xaml
<Page x:Class="XamlDemo.Contracts.SearchContract.RemoteSuggestion" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Contracts.SearchContract" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" Text="本例演示如何使用 Search Contract 的搜索建议,数据源在服务端。同时演示如何为搜索建议增加图标、描述等" /> </StackPanel> </Grid> </Page>
Contracts/SearchContract/RemoteSuggestion.xaml.cs
/* * 本例演示如何使用 Search Contract 的搜索建议,数据源在服务端。同时演示如何为搜索建议增加图标、描述等 * * SearchPane - 搜索面板 * SuggestionsRequested - 用户的查询文本发生改变,app 需要提供新的建议时所触发的事件(事件参数 SearchPaneSuggestionsRequestedEventArgs) * ResultSuggestionChosen - 提交搜索建议对象时所触发的事件(除了查询文本,还有图标和描述信息的) * 这里所谓的搜索建议对象就是通过 AppendResultSuggestion(string text, string detailText, string tag, IRandomAccessStreamReference image, string imageAlternateText) 构造的搜索建议 * QuerySubmitted - 提交搜索字符串时所触发的事件(只有文本信息的) * * SearchPaneSuggestionsRequestedEventArgs - 当需要提供新的建议时所触发的事件 * QueryText - 搜索文本 * Request - 关于建议信息的对象,返回 SearchPaneSuggestionsRequest 类型的数据 * SearchPaneQueryLinguisticDetails - 关于输入法编辑器信息(IME)的对象,返回 SearchPaneQueryLinguisticDetails 类型的数据 * * SearchPaneSuggestionsRequest - 关于建议信息的对象 * SearchSuggestionCollection - 搜索面板的搜索建议集合 * Size - 搜索建议的数量,最多只支持 5 个元素,就算超过 5 个系统也只会显示前 5 个 * AppendQuerySuggestion() & AppendQuerySuggestions() - 将指定的建议信息添加到搜索面板的建议集合中 * AppendSearchSeparator() - 添加一个分割,可以指定分隔符左侧的文本 * AppendResultSuggestion(string text, string detailText, string tag, IRandomAccessStreamReference image, string imageAlternateText) - 增加一个搜索建议对象 * text - 建议结果的文本 * detailText - 描述 * tag - 附加数据,可以在 ResultSuggestionChosen 事件的事件参数中获取此值 * image - 图标 * imageAlternateText - 图像的替换文字 * GetDeferral() - 获取异步操作对象,同时开始异步操作,之后通过 Complete() 通知完成异步操作 */ using System; using System.Net.Http; using System.Threading.Tasks; using Windows.ApplicationModel.Search; using Windows.Data.Json; using Windows.Storage.Streams; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Contracts.SearchContract { public sealed partial class RemoteSuggestion : Page { private SearchPane _searchPane; // 用于获取远程建议的 HttpClient private HttpClient _httpClient; // 当前的 HttpClient 请求任务 private Task<string> _currentHttpTask; public RemoteSuggestion() { this.InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 获取当前的 SearchPane,并注册相关事件 _searchPane = SearchPane.GetForCurrentView(); _searchPane.SuggestionsRequested += _searchPane_SuggestionsRequested; // 如果用户提交的搜索数据是通过 AppendResultSuggestion(string text, string detailText, string tag, IRandomAccessStreamReference image, string imageAlternateText) 而来的,则触发此事件 _searchPane.ResultSuggestionChosen += _searchPane_ResultSuggestionChosen; // 如果用户提交的搜索数据是字符串,则触发此事件 _searchPane.QuerySubmitted += _searchPane_QuerySubmitted; _httpClient = new HttpClient(); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 取消相关事件的监听 _searchPane.SuggestionsRequested -= _searchPane_SuggestionsRequested; _searchPane.ResultSuggestionChosen -= _searchPane_ResultSuggestionChosen; _searchPane.QuerySubmitted -= _searchPane_QuerySubmitted; if (_httpClient != null) { _httpClient.Dispose(); _httpClient = null; } } async void _searchPane_SuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args) { // 异步操作 var deferral = args.Request.GetDeferral(); try { // 根据用户的输入,从远程获取建议列表 Task task = GetTaobaoSuggestionsAsync("http://suggest.taobao.com/sug?extras=1&code=utf-8&q=" + args.QueryText, args.Request.SearchSuggestionCollection); await task; lblMsg.Text = "TaskStatus: " + task.Status.ToString(); } finally { // 完成异步操作 deferral.Complete(); } } void _searchPane_ResultSuggestionChosen(SearchPane sender, SearchPaneResultSuggestionChosenEventArgs args) { lblMsg.Text = "ResultSuggestionChosen: " + args.Tag; } void _searchPane_QuerySubmitted(SearchPane sender, SearchPaneQuerySubmittedEventArgs args) { lblMsg.Text = "QuerySubmitted: " + args.QueryText; } private async Task GetTaobaoSuggestionsAsync(string str, SearchSuggestionCollection suggestions) { // 取消之前的 HttpClient 请求任务 if (_currentHttpTask != null) _currentHttpTask.AsAsyncOperation<string>().Cancel(); // 新建一个 HttpClient 请求任务,以从远程获取建议列表数据 _currentHttpTask = _httpClient.GetStringAsync(str); string response = await _currentHttpTask; // 将获取到的数据放到建议列表中 JsonObject jb = JsonObject.Parse(response); var ary = jb["result"].GetArray(); foreach (JsonValue jv in ary) { // 图文方式显示建议数据 RandomAccessStreamReference imageStreamRef = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/Logo.png", UriKind.Absolute)); suggestions.AppendResultSuggestion(jv.GetArray()[0].GetString(), "detailText", jv.GetArray()[0].GetString(), imageStreamRef, "imageAlternateText"); suggestions.AppendSearchSeparator("separator"); // 建议列表最多只支持 5 个元素,超过 5 个也只会显示前 5 个 if (suggestions.Size >= 5) break; } } } }
4、本例演示如何使用 Search Contract 的基于本地文件的搜索建议,数据来源于文件的 metadata
Contracts/SearchContract/LocalFileSuggestion.xaml
<Page x:Class="XamlDemo.Contracts.SearchContract.LocalFileSuggestion" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Contracts.SearchContract" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" Text="本例演示如何使用 Search Contract 的基于本地文件的搜索建议,数据来源于文件的 metadata" /> </StackPanel> </Grid> </Page>
Contracts/Sear0chContract/LocalFileSuggestion.xaml.cs
/* * 本例演示如何使用 Search Contract 的基于本地文件的搜索建议,数据来源于文件的 metadata * * SearchPane - 搜索面板 * SetLocalContentSuggestionSettings() - 指定一个 LocalContentSuggestionSettings 对象,以实现基于本地文件的搜索建议 * * LocalContentSuggestionSettings - 基于本地文件的搜索建议的相关配置 * Enabled - 是否启用 * Locations - 搜索路径 * AqsFilter - AQS 字符串,参见 http://msdn.microsoft.com/zh-cn/library/windows/apps/aa965711.aspx * PropertiesToMatch - 用于提供搜索建议的文件属性列表,默认会使用所有可用的文件属性 * * * 注:AQS 全称 Advanced Query Syntax */ using Windows.ApplicationModel.Search; using Windows.Storage; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; namespace XamlDemo.Contracts.SearchContract { public sealed partial class LocalFileSuggestion : Page { public LocalFileSuggestion() { this.InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 实例化 LocalContentSuggestionSettings var settings = new LocalContentSuggestionSettings(); settings.Enabled = true; // 指定需要搜索的文件夹为 KnownFolders.MusicLibrary(需要在 Package.appxmanifest 的“功能”中选中“音乐库”) settings.Locations.Add(KnownFolders.MusicLibrary); // 在当前的 SearchPane 中启用指定的 LocalContentSuggestionSettings SearchPane.GetForCurrentView().SetLocalContentSuggestionSettings(settings); } } }
OK
[源码下载]