2012年9月
Windows 8用户体验的关键特点之一是对超级按钮的使用。它响应轻扫或Windows徽标+C键,并从屏幕右侧滑出。这些按钮(“超级按钮”)为Windows应用商店应用提供了一种以一致方式在应用程序之间公开常用功能的手段。例如,如果您需要在应用程序中执行搜素,您可以选择搜索超级按钮并在搜索窗格中输入一个搜索条目。用户界面和调用上述界面的操作在每个应用程序中都是一样的。为了与另一个应用程序共享数据,您使用共享超级按钮。一个支持共享的应用程序就可以共享数据了。例如,一个绘图应用程序可以与其他支持共享的应用程序共享图画,或者Contoso Cookbook可以与其他支持共享的应用程序共享食谱,
在本实验中,您将为Contoso Cookbook添加搜索和共享支持。您将获得实现搜索和共享合约的第一手体验。您将同时学习这些合约如何为两个应用程序之间或应用程序与Windows自身之间提供更高层次的集成。
本实验将向您展示如何:
您需要下列软件完成本实验:
您必须执行以下步骤来准备本实验室的计算机:
本动手实验包含以下练习:
完成本实验的预计时间:30至40分钟。
在练习1中您将向Contoso Cookbook添加共享支持,这样食谱就可以被其他应用程序共享。您将对每个食谱共享两类数据:包含食谱名称、原料以及指南的文字数据和代表食谱图形的图像数据。
首先,让我们查看共享支持被添加之前,当共享超级按钮在Contoso Cookbook中被调用时,它的行为方式。
1、在Visual Studio中打开您在实验2中完成的ContosoCookbook项目。如果您尚未完成实验2或希望从一个参考副本开始,您可以在开始材料中找到实验已完成的版本。
2、按F5以启动Contoso Cookbook。
3、点击某个食谱以显示项-明细页面。
4、从屏幕右侧从右向左轻扫以显示超级按钮,或按Windows徽标+C键。
5、点击共享超级按钮以显示共享窗格。
6、由于Contoso Cookbook目前尚未实现共享合约,共享窗格通知您“此应用无法共享。”
7、返回Visual Studio并停止调试。
现在您已经查看了当某个应用程序不支持共享时共享窗格的外观,让我们向Contoso Cookbook添加共享合约。首先,我们需要添加一些基础设施以支持上述合约。
1、打开ItemDetailPage.xaml.cs并在文件的顶部添加以下using语句。
C#
using Windows.ApplicationModel.DataTransfer; using System.Text; using Windows.Storage.Streams;
2、找到LoadState方法并在最后添加以下语句。
C#
// Register for DataRequested events DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;
3、现在向ItemDetailPage类添加以下方法。
C#
void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args) { var request = args.Request; var item = (RecipeDataItem)this.flipView.SelectedItem; request.Data.Properties.Title = item.Title; request.Data.Properties.Description = "Recipe ingredients and directions"; // Share recipe text var recipe = "\r\nINGREDIENTS\r\n"; recipe += String.Join("\r\n", item.Ingredients); recipe += ("\r\n\r\nDIRECTIONS\r\n" + item.Directions); request.Data.SetText(recipe); }
注意:您通过为DataTransferManager的 DataRequested事件注册一个处理程序以实现共享。当用户激活共享超级按钮时,这些事件将被触发。在本例中,您通过调用由args.Request.Data公开的 DataPackage对象的SetText方法以响应上述事件并以文字方式提供食谱信息。当包含共享目标列表的共享窗格出现时,列表仅包含能够使用文本的共享目标。
4、找到SaveState方法并在方法最后添加以下语句。
C#
// Deregister the DataRequested event handler DataTransferManager.GetForCurrentView().DataRequested -= OnDataRequested;
5、按F5以启动应用程序。
6、点击某个食谱以显示食谱-明细页面。
7、显示超级按钮并选择共享超级按钮以显示共享窗格。共享窗格现在显示安装在您设备上的共享目标列表,共享目标指可以使用共享源共享的数据的应用程序。
注意:如果您还未执行以上操作,现在就可以安装Windows 8 SDK示例包中的共享目标示例(Share Target Sample)应用程序。共享目标示例应用程序演示了如何编写可作为共享目标的应用程序。更重要的是它提供了一个共享目标以测试您开发的作为共享源的应用程序。它可以接收图像、文本以及其他数据类型。如果需要安装此示例,在Visual Studio中打开它并运行一次。然后当您从Windows应用商店应用选择共享超级按钮时,它就会出现在共享目标列表中。
8、在共享窗格中选择一个共享目标并验证它将收到食谱数据。图1显示了在接收Contoso Cookbook的食谱文本后的共享目标示例应用程序。
图1 显示某个食谱的共享目标示例应用程序
9、返回Visual Studio并停止调试。
Contoso Cookbook现在可以共享文本食谱数据,但是由于每个食谱有一个图像,它应该也能够共享食谱图像。这样接收图像的共享目标就可以显示食谱的一张图片和食谱文本(假设共享目标支持文本和图像)。让我们修改共享代码以支持位图图像和文本。
1、返回在之前任务中添加的OnDataRequested方法。
2、在方法最后添加以下语句。
C#
// Share recipe image var reference = RandomAccessStreamReference.CreateFromUri(new Uri(item.ImagePath.AbsoluteUri)); request.Data.Properties.Thumbnail = reference; request.Data.SetBitmap(reference);
3、按F5以启动应用程序。
4、点击某个食谱以显示食谱-明细页面。
5、显示超级按钮并选择共享超级按钮以显示共享窗格。
6、在共享窗格中选择一个共享目标并验证它将收到食谱图像。图2显示了在接收Contoso Cookbook的食谱图像后的共享目标示例应用程序。
图2 显示某个食谱图像的共享目标示例应用程序
7、返回Visual Studio并停止调试。
在练习2中您将向Contoso Cookbook添加搜索支持,这样用户就可以使用搜索超级按钮对食谱数据进行搜索。例如想在所有食谱中找到含糖食谱的用户可以调用搜索超级按钮,在搜索框中输入“sugar”,含糖食谱列表就会被呈现给用户。
在向Contoso Cookbook添加搜索支持前,让我们查看当Contoso Cookbook在前台运行且搜索超级按钮被调用时搜索用户界面的外观。
1、按F5以启动应用程序。
2、从屏幕右侧从右向左轻扫以显示超级按钮,或按Windows徽标+C键。
3、点击搜索超级按钮以显示搜索窗格。
4、在搜索框中输入“sugar”(不含引号)并按回车,或点击搜索框右侧的放大镜图标。
5、Windows告诉您“无法搜索此应用。”一旦当您向Contoso Cookbook添加搜索支持后结果就会改变。
6、返回Visual Studio并停止调试。
现在让我们在Contoso Cookbook中实现搜索合约。Visual Studio将通过在应用程序中插入一个C#合约为您完成绝大部分工作。您需要调整代码以针对应用程序数据执行特定的搜索。它实现起来很简单,在接下来的几步中将进行演示。
1、在解决方案管理器中右键单击项目并使用Add > New Item命令添加名称为SearchResultsPage.xaml的合约,如图3所示。
图3 添加一个搜索合约
2、在SearchResultsPage.xaml的<Pages.Resources>部分,在名称为“AppName”的字符串资源中,将“My Application”修改为“Search”以修改页面顶部的标题。
XAML
<x:String x:Key="AppName">Search</x:String>
3、向名称为“resultsGridView”的GridView和名称为“resultsListView”的ListView添加ItemClick=”OnItemClick”属性。当应用程序未被贴靠时,GridView显示搜索结果,当应用程序被贴靠时,ListView用于显示搜索结果。
4、打开SearchResultsPage.xaml.cs并向SearchResultsPage类添加以下方法,以在搜索结果页面中单击某个项时导航至食谱页面。
C#
private void OnItemClick(object sender, ItemClickEventArgs e) { // Navigate to the page showing the recipe that was clicked this.Frame.Navigate(typeof(ItemDetailPage), ((RecipeDataItem)e.ClickedItem).UniqueId); }
5、在SearchResultsPage.xaml.cs的顶部添加以下using语句。
C#
using ContosoCookbook.Data;
6、接着向SearchResultsPage类添加以下字段。
C#
// Collection of RecipeDataItem collections representing search results private Dictionary<string, List<RecipeDataItem>> _results = new Dictionary<string, List<RecipeDataItem>>();
7、转至LoadState方法并在“Communicate results through the view model.”注释前添加以下语句。
C#
// Search recipes and tabulate results var groups = RecipeDataSource.GetGroups("AllGroups"); string query = queryText.ToLower(); var all = new List<RecipeDataItem>(); _results.Add("All", all); foreach (var group in groups) { var items = new List<RecipeDataItem>(); _results.Add(group.Title, items); foreach (var item in group.Items) { if (item.Title.ToLower().Contains(query) || item.Directions.ToLower().Contains(query)) { all.Add(item); items.Add(item); } } filterList.Add(new Filter(group.Title, items.Count, false)); } filterList[0].Count = all.Count;
注意:您刚添加的代码根据用户输入的查询文本对所有食谱标题和指南进行搜索。对每个匹配的食谱,它将向变量名为all的食谱列表添加一个RecipeDataItem,并在每个特定组中向变量名为items的食谱列表添加一个RecipeDataItem。上述列表在您刚声明的字典中被维护,并根据“All”, “Chinese”等组名称被标记。
上述代码同时填充搜索结果页面顶部的筛选列表(由filterList变量代表),筛选列表包含组名称,并显示每个组中匹配的食谱数。
8、找到Filter_SelectionChanged方法并向if子句(紧挨在// TODO: Respond to the change in active filter注释后)添加以下语句。
C#
this.DefaultViewModel["Results"] = _results[selectedFilter.Name];
9、在Common文件夹中打开StandardStyles.xaml。
10、找到名称为“StandardSmallIcon300x70ItemTemplate”的DataTemplate。删除绑定到Subtitle属性的TextBlock。同时修改Border的width和height属性,以及将第一个TextBlock的Text属性绑定到ShortTitle而非Title。
XAML
<DataTemplate x:Key="StandardSmallIcon300x70ItemTemplate"> <Grid Width="294" Margin="6"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,0,0,10" Width="60" Height="45"> <Image Source="{Binding Image}" Stretch="UniformToFill"/> </Border> <StackPanel Grid.Column="1" Margin="10,-10,0,0"> <TextBlock Text="{Binding ShortTitle}" Style="{StaticResource BodyTextStyle}" TextWrapping="NoWrap"/> <TextBlock Text="{Binding Description}" Style="{StaticResource BodyTextStyle}" Foreground="{StaticResource ApplicationSecondaryForegroundThemeBrush}" TextWrapping="NoWrap"/> </StackPanel> </Grid> </DataTemplate>
11、按F5以启动应用程序。
12、显示超级按钮。
13、点击搜索超级按钮并显示搜索窗格。
14、在搜索窗格顶部的搜索框中输入“sugar”(不含引号)并按回车,或点击搜索框右侧的放大镜图标。
15、验证五个食谱出现在搜索结果中(见图4)。
图4 针对 “sugar”的搜索结果
16、选择其中的某个食谱并验证食谱明细将出现。
17、返回Visual Studio并停止调试。
一个可以添加至搜索体验的有用的增强是当用户在搜索框中输入一个搜索条目时提供相应的搜索建议。它实现起来很简单。您需要做的就是为SuggestionsRequested事件注册一个处理程序。下面是它的实现方法。
1、打开App.xaml.cs并在文件顶部添加以下using语句。
C#
using Windows.ApplicationModel.Search;
2、在OnLaunched方法的开始处紧挨着加载食谱数据的RecipeDataSource.LoadLocalDataAsync或RecipeDataSource.LoadRemoteDataAsync的调用后,添加以下语句。
C#
// Register handler for SuggestionsRequested events from the search pane SearchPane.GetForCurrentView().SuggestionsRequested += OnSuggestionsRequested;
3、现在向Application类添加以下方法。
C#
void OnSuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args) { string query = args.QueryText.ToLower(); string[] terms = { "salt", "pepper", "water", "egg", "vinegar", "flour", "rice", "sugar", "oil" }; foreach(var term in terms) { if (term.StartsWith(query)) args.Request.SearchSuggestionCollection.AppendQuerySuggestion(term); } }
注意:您刚添加的代码为匹配salt, pepper, water, egg, vinegar, flour, rice, sugar和oil等模式的单词提供搜索建议。如果用户输入“sa”,单词“salt”将作为建议的完整条目出现在搜索窗格。当然只要您愿意,您可以添加尽可能多的建议。如果您希望在用户输入“ke”时出现“ketchup”,只需简单地向列表中添加该条目。
4、再次启动应用程序并在搜索框中输入“su”。验证“sugar”将出现在搜索框下面的建议列表中,如图5所示。
图5 运行中的搜索建议
5、返回Visual Studio并停止调试。
您快完成工作了,但仍然需要执行一项任务。目前当Contoso Cookbook运行时搜索工作良好。但是如果用户从应用程序外调用搜索,它根本不能工作。为亲自查看,确认Contoso Cookbook未运行(您可以在任务管理器中对它进行检查,如果需要可以结束该任务)。然后调用搜索超级按钮,在搜索框中输入“sugar”,并在搜索窗格的应用程序列表中点击Contoso Cookbook。您将注意到没有符合搜索的结果。让我们进行修改。
1、打开App.xaml.cs并找到OnSearchActivated方法。
注意:OnSearchActivated是Application类中一个关键的虚拟方法。当用户执行搜索时它被调用以激活搜索结果页面,并且它在您向项目添加搜索合约时被添加至App.xaml.cs。如果操作系统从搜索窗格启动Contoso Cookbook,OnSearchActivated将替代OnLaunched而被调用。如果发生这种情况,在激活搜索结果页面前,我们需要重新初始化应用程序。
2、在OnSearchActivated方法的开始部分添加以下语句。
C#
// Reinitialize the app if a new instance was launched for search if (args.PreviousExecutionState == ApplicationExecutionState.NotRunning || args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser || args.PreviousExecutionState == ApplicationExecutionState.Terminated) { // Load recipe data await RecipeDataSource.LoadLocalDataAsync(); // Register handler for SuggestionsRequested events from the search pane SearchPane.GetForCurrentView().SuggestionsRequested += OnSuggestionsRequested; }
注意:如果您希望从云中而不是从本地资源加载食谱数据,在以上代码中用LoadRemoteDataAsync调用替换LoadLocalDataAsync调用,与您在实验1中的做法一样。
3、使用任务管理器以确认Contoso Cookbook未运行。如果运行则结束该任务。
4、转至开始屏幕。显示超级按钮并点击搜索超级按钮。
5、输入搜索条目“sugar”。然后在搜索窗格的应用程序列表中点击Contoso Cookbook。
6、验证Contoso Cookbook将会被启动并显示正确的搜索结果。
7、按Alt-F4关闭应用程序。
合约是Windows 8的重要组成部分,因为它们允许应用程序与操作系统进行集成,并且它们提供了应用程序间一致并可预见的用户体验。这个松耦合的协作是非常协同和可扩展的,它允许您与任何应用程序共享任何内容,在任何应用内搜索。
在本实验中您学习了两类合约:共享合约和搜索合约。在以后的实验中,您将使用另一类合约以对设置进行集成。但是首先还有其他内容需要处理:使用大多数内置于PC和移动设备的照相机实现媒体捕获。这是下一个实验的主题,因此让我们继续前进!