Hands-On Lab
Launchers 和 Choosers
Lab version: 1.0.0
Last updated: 2/29/2012
目录
Launchers和Choosers框架使Windows Phone应用程序可以为用户提供一些功能,比如拨打电话,发送电子邮件,选择图片等。
Windows Phone应用程序模型使每个应用程序的执行(包括内存隔离)以及文件存储相互隔离。 Windows Phone应用程序不能直接读取一些信息,比如联系人列表,也不能直接启动另外一个应用程序,比如拨号应用程序和短信息应用程序。为了支持一些一般任务比如拨打电话或者发送短信息,Windows Phone提供了一系列Launcher和Chooser使应用程序可以间接完成这些事情。Launchers和Choosers切换当前应用程序至内置应用程序,并在将当前运行的应用程序切换至后台的时候提供一种无缝的体验。
该框架分为以下两部分:
· Launcher- 一个“没有返回信息” 的动作, 它可以调用一个特定的手机功能,比如发送短信息,打开一个Web页面,或者拨打电话
· Chooser –一个 “打开文件对话框” 的动作, 它可以选择一个特定应用程序存储区域的信息,比如选择电子邮件地址,联系人,或者照片。
以下是代号为“芒果”的Windows Phone 7提供的完整的Launcher和Chooser列表:
Launcher
· EmailComposeTask – 撰写新的电子邮件
· MarketplaceDetailTask – 启动Marketplace并显示指定应用程序的详细信息
· MarketplaceHubTask –启动Marketplace
· MarketplaceReviewTask –启动Marketplace以便为当前应用程序提供评论
· MarketplaceSearchTask –启动Marketplace并执行相关内容的搜索
· MediaPlayerLauncher –启动媒体播放器
· PhoneCallTask – 向指定的号码拨打电话
· SaveEmailAddressTask – 撰写新的电子邮件
· SavePhoneNumberTask –保存电话号码
· SearchTask –启动网页搜索应用程序
· SmsComposeTask –撰写新的短信息
· WebBrowserTask –可以启动Web浏览器到指定的URL
Choosers
· EmailAddressChooserTask – 从联系人列表中选择一个电子邮件地址
· CameraCaptureTask – 打开照相机应用程序以便拍照
· PhoneNumberChooserTask –从联系人列表中选择一个电话号码
· PhotoChooserTask – 从PictureGallery中选择一张图片
· Contacts –根据姓名,电子邮件地址,电话号码搜索联系人.
· Appointments –搜索一段时间内的用户的日程安排
应用程序什么时候会被墓碑化?
一般来说,当用户向前导航并离开当前应用程序的时候,应用程序会被墓碑化(即,应用程序被放置到到回退栈中)。当然也有少数例外,当系统需要额外的资源来激活应用程序时,处于后台运行的应用程序会被墓碑化。
当启动一些特殊的任务的时候,应用程序不会被自动墓碑化,这样使得用户感觉这些操作像是应用程序原生的功能。这些任务帮助用户完成一些功能,比如选择照片。避免墓碑化可以保证应用程序和这些特殊的任务之间的平滑过渡(比如,当选择一张图片回到应用程序的过程之间不会感觉到延迟)。
下面是这些任务,当他们被调用的时候,调用它的应用程序不会自动被墓碑化:
· PhotoChooserTask
· CameraCaptureTask
· MediaPlayerLauncher
· EmailAddressChooserTask
· PhoneNumberChooserTask
有三种场景在后台的应用程序会被立即墓碑化:
· 用户向前导航并离开应用程序(比如用户按下开始键)
· 应用程序启动一些不在上述列表中的 launchers或者choosers
· 系统需要更多的资源来运行当前激活状态的应用程序
注意: 所有上述关于墓碑化的信息均针对Windows Phone 7.0有效。在Windows phone 7.1上,所有的launchers和choosers都不会导致应用程序墓碑化,但是应用程序仍然可能被墓碑化,如果系统需要更多的资源。更多关于最新的Windows phone 7.1应用程序执行模型的信息请参考相关文档。
目标
完成本实验, 你将会:
· 熟悉Windows Phone 7应用程序模型的Launcher和Choosers的概念
· 明白怎样和什么时候使用launchers 和 choosers
· 创建一个Silverlight应用程序使用各种launchers 和 choosers
前提条件
完成本动手实验需要满足以下要求:
· 安装MicrosoftVisual Studio 2010 Express for Windows Phone 或者 Microsoft Visual Studio2010
· Windows Phone 7.1 Developer Tools
Note: 你可以从以下链接下载所有这些工具 http://go.microsoft.com/?linkid=9772716.
实验提纲
这个动手实验由以下两个练习组成:
· WindowsPhone Launchers介绍及使用
· WindowsPhone Choosers介绍及使用
完成本实验需要花费时间: 45 分钟.
练习 1: Launchers介绍及使用
在本练习中,你将新建一个解决方案完成以下任务:
· 添加页面并在多个页面之间导航
· 在每个页面中实现一个不同的launcher
MicrosoftVisual Studio 2010 Express for Windows Phone被用作开发环境,WindowsPhone Emulator 被用作调试工具.
解决方案选择 Silverlight for WindowsPhone Panorama Application模板. 在开发中,启动页面是一个 Silverlight for Windows Phone 项目文件:Windows Phone Portrait 页面.
注意: 这个动手实验描述的过程是使用Microsoft Visual Studio 2010 Express for Windows Phone, 但是同样适用于 Microsoft Visual Studio2010.
任务 1 – 添加页面和导航页面
在本任务中,提供了一个起始的解决方案,这个解决方案包括一个简单的Windows Phone 7 全景视图应用程序,包含一个主页,以及为下一个任务做了些准备.
1. 打开 MicrosoftVisual Studio 2010 Express for Windows Phone : 开始 | 所有应用程序| Microsoft Visual Studio 2010 Express | Microsoft Visual Studio 2010Express for Windows Phone.
Visual Studio 2010: 打开Visual Studio 2010 : start | AllProgram| Microsoft Visual Studio 2010.
2. 从菜单中选择文件.文件的下拉菜单将会显示.
3. 从 文件 的下拉菜单中, 选中 打开项目. 打开项目的窗口将会显示.
Visual Studio 2010: 在文件下拉菜单中, 指向 Open Project/Solution.
4. 导航到这个实验的启动项目位置:Source\Ex1-Launchers\Begin , 选择 LaunchersAndChoosers.sln, 单击打开.
图 1
正在打开开始解决方案
5. 检查打开的项目:
◦ 这是一个标准的Windows Phone 全景视图应用程序, 包含自定义的 MainPage.xaml, MainPage.xaml.cs文件, 在 App.xaml中添加了一些资源, 去掉了model 中的类(为了简便), 修改了启动图片 SplashScreenImage.jpg. 这个应用程序还包括一个资源文件ResourceDictionary.xaml,它用来调整界面.
◦ 项目添加了一个名叫“Views”的文件夹,它将用来保存本次任务中新添加的页面
◦ 项目添加了两个文件夹:“Toolkit.Content” 和 “Images”,它们用来保存一些应用程序的图片
◦ 项目包括一个 “Media”文件夹用来保存媒体资源
◦ 项目包括一个 “Converters”文件夹包括一些本实验会用到的转换器.
6. 给项目添加一个页面:
◦ 右击 Views 文件夹
◦ 从 下拉菜单中选择Add
◦ 从 Add下拉菜单中选择 New Item
图 2
添加新的页面
注意: 可以使用以下方式替代, 在单击 “Views” 文件夹的同时按住 “Ctrl+Shift+A”.
7. 选择 “Windows Phone Portrait Page” 模板, 命名新的页面叫 SavePhoneNumberPage, 单击 Add.
图 3
添加新的页面
VisualStudio 设计器会自动打开新建的页面文件.
8. 如果Visual Studio 设计器没有自动打开, 双击新建的页面文件SavePhoneNumberPage.xaml.
9. 定位到 PhoneApplicationPage 元素.
10. 修改 SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.SavePhoneNumberPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
11. 定位到名为TitlePanel的Stackpanel.
12. 设置应用程序标题为PHONE SERVICES,设置页面标题为Save Phone ,并且根据以下示例修改Text属性。注意通过使用 “StaticResourceAppName” ,文本将会被绑定到一个静态资源,你可以在App.xaml中找到:
XAML
<TextBlock x:Name="ApplicationTitle"
Text="{StaticResourceAppName}"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle"
Text="Save Phone"
Margin="-3,-8,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
13. 定位到名为 ContentPanel 的Grid.
14. 通过添加RowDefinitions 定义Grid为3行:
XAML
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
Grid的第一行用来放置一个StackPanel,它包含一个TextBlock和一个TextBox 用来输入电话号码.通过设置 InputScope 属性指示显示数字键盘
15. 添加下面高亮部分的ContentPanel:
XAML
<!--ContentPanel- place additional content here-->
<Gridx:Name="ContentPanel" Grid.Row="1">
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0">
<TextBlock Style="{StaticResource TextBlockTitleLargeStyle }" Text="Please enter phonenumber:"/>
<TextBox x:Name="txtInput" InputScope="TelephoneNumber"/>
</StackPanel>
</Grid>
注意: 当开发Silverlight Applications for Windows Phone应用程序的时候,其中一个应该熟悉的概念是软键盘. 软键盘是一个虚拟的键盘,当一个文本输入控件比如TextBox得到输入焦点之后会自动出现,而不需要代码调用,这个过程是自动的。但是Silverlight能够为每个输入控件指定输入范围 ,这允许系统在运行时根据要输入数据的类型使软键盘显示不同的样式和键. 为了实现这个功能,设置输入控件的InputScope 属性.
Grid的最后一个行放置一个stack panel,其中放置一些Button.
16. 在前面插入的StackPanel后面添加一个StackPanel到Grid的第二行,并放置一个Button用来保存号码,代码如下:
XAML
<StackPanel Orientation="Vertical" Grid.Row="2" VerticalAlignment="Bottom">
<Button x:Name="btnSavePhone" Content="SavePhone Number" Height="100" Margin="0,5" Click="btnSavePhone_Click"/>
</StackPanel>
17. 双击 SavePhoneNumberPage.xaml.cs 文件切换到后台代码,并添加btnSavePhone_Click事件,代码如下:
C#
private void btnSavePhone_Click(object sender, RoutedEventArgse)
{
}
18. 现在页面创建成功,接下来添加从MainPage到这个页面之间的导航
19. 打开 MainPage.xaml.cs 并且定位到如下注释部分:
C#
private void btnSavePhoneNumber_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to save phone number page
}
20. 用下面的代码替换掉注释部分:
C#
private void btnSavePhoneNumber_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
newUri("/Views/SavePhoneNumberPage.xaml",UriKind.Relative));
}
21. 按F5编译并运行程序 ,WindowsPhone模拟器将会启动.
图 5
在WindowsPhone模拟器中运行应用程序
22. 单击 Save Phone Number 并检查导航是否正常.
23. 单击textbox确认软键盘是否按电话号码格式显示. 由于保存号码的代码还没有编写,所以单击保存按钮没有反应.
图 6
电话号码格式的软键盘
24. 在 Visual Studio 中按 SHIFT+F5 停止调试并回到编辑模式.
25. 添加一个名为SaveEmailAddressPage 的页面至Views 文件夹,使用"Windows Phone Portrait Page" 模板
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择 New Item.
26. 如果新建的页面没有自动打开,双击新建的页面打开Visual Studio设计器
27. 定位到 PhoneApplicationPage 元素.
28. 修改 SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.SaveEmailAddressPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
29. 为了简化设计过程,用下面的代码替换整个 LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Save Email"Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1" Margin="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0">
<TextBlock Style="{StaticResourceTextBlockTitleLargeStyle}" Text="Please enteremail address:"/>
<TextBox x:Name="txtInput"InputScope="EmailUserName"/>
</StackPanel>
<StackPanel Orientation="Vertical"Grid.Row="2"
VerticalAlignment="Bottom">
<Button x:Name="btnSaveEmail"Content="Save Email Address" Margin="0,5" Click="btnSaveEmail_Click"/>
</StackPanel>
</Grid>
</Grid>
注意: 这次输入文本框需要支持Email格式的输入,因此设置不同的InputScope 来显示不同风格的软键盘.
上述标记语言代码使页面呈现如下的样子:
图 7
Email格式的软键盘
30. 打开 SaveEmailAddressPage.xaml.cs.
31. 添加下面的 btnSaveEmail_Click事件至末尾.
C#
private void btnSaveEmail_Click(object sender, RoutedEventArgse)
{
}
32. 打开 MainPage.xaml.cs 文件定位到如下注释的地方:
C#
private void btnSaveEmail_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to save email address page
}
33. 用下面的代码替换注释部分:
C#
private void btnSaveEmail_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
new Uri("/Views/SaveEmailAddressPage.xaml",
UriKind.Relative));
}
34. 添加一个新的页面SearchTaskPage 到 Views 文件夹,使用"Windows Phone Portrait Page" 模板.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item
35. 定位到PhoneApplicationPage 元素.
36. 修改SupportedOrientations属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.SearchTaskPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
37. 为了简化设计过程, 用下面的代码替换整个 LayoutRoot :
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Search Task"Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"Grid.Row="0">
<TextBlock Text="Define search terms:"
Style="{StaticResource TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtInput"InputScope="Search"/>
</StackPanel>
<StackPanel Orientation="Vertical"Grid.Row="2">
<Button x:Name="btnSearch"Content="Search Everywhere" Margin="0,5" Click="btnSearch_Click"/>
</StackPanel>
</Grid>
</Grid>
前面的标记语言代码呈现如下的样子:
图 8
搜索页面
38. 打开 SearchTaskPage.xaml.cs.
39. 添加 btnSearch_Click事件到SearchTaskPage.xaml.cs 文件中代码的末尾:
C#
private void btnSearch_Click(object sender, RoutedEventArgse)
{
}
40. 打开 MainPage.xaml.cs 页面并定位到如下注释的部分:
C#
private void btnSearchTask_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to search task page
}
41. 使用以下的代码替换掉注释部分:
C#
private void btnSearchTask_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/SearchTaskPage.xaml", UriKind.Relative));
}
42. 添加新的页面WebSearchPage 到Views 文件夹,使用 "Windows Phone Portrait Page" 模板.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item
43. 定位到PhoneApplicationPage 元素.
44. 修改SupportedOrientations属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.WebSearchPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
45. 为了简化设计过程,使用如下的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Search Web" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"Grid.Row="0">
<TextBlock Text="Phrase:" Style="{StaticResource TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtInput"InputScope="Text"/>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.Row="1">
<Button x:Name="btnGo" Content="Search With Bing" Margin="0,5" Click="btnGo_Click"/>
</StackPanel>
</Grid>
</Grid>
上述标记语言代码使界面看起来像这样:
图 9
浏览Web页面
46. 打开 WebSearchPage.xaml.cs.
47. 添加 btnGo_Click事件到 WebSearchPage.xaml.cs 页面:
C#
private void btnGo_Click(objectsender, RoutedEventArgs e)
{
}
48. 打开 MainPage.xaml.cs 文件定位到以下注释部分:
C#
private void btnSearchWithBing_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to search with bing page
}
49. 用下面的代码替换掉注释部分:
C#
private void btnSearchWithBing_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/WebSearchPage.xaml", UriKind.Relative));
}
50. 添加一个新的页面VideoPlayerPage 至Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
51. 修改SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.VideoPlayerPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
52. 为了简化设计过程,使用以下的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource AppName}" Style="{StaticResourcePhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Play Video"Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<StackPanel Grid.Row="0" Orientation="Vertical">
<Button Content="Play Video" x:Name="btnPlayVideo"Click="btnPlayVideo_Click"/>
</StackPanel>
</Grid>
</Grid>
上述标记描述语言代码使界面看起来像下面的样子:
图 10
视频播放器页面
53. 添加下面的事件至VideoPlayerPage.xaml.cs:
C#
private void btnPlayVideo_Click(object sender, RoutedEventArgse)
{
}
54. 添加新的导航命令至MainPage.xaml.cs. 定位到注释部分:
C#
private void btnShowVideo_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to show video page
}
用下面的代码替换掉注释部分:
C#
private void btnShowVideo_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/VideoPlayerPage.xaml", UriKind.Relative));
}
55. 添加一个新的页面SaveRingtonePage 到Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
56. 修改 SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.SaveRingtonePage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
57. 为了简化设计过程,使用下面的代码替换掉整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Save Ringtone"Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1" Margin="0">
<StackPanel Grid.Row="0" Orientation="Vertical">
<Button Content="Save Ringtone" x:Name="btnSaveRingtone"Click="btnSaveRingtone_Click"/>
</StackPanel>
</Grid>
</Grid>
上述标记描述语言使界面看起来像下面的样子:
图 11
保存铃音页面
58. 添加下面的事件到SaveRingtonePage.xaml.cs:
C#
private voidbtnSaveRingtone_Click(object sender, RoutedEventArgs e)
{
}
59. 在 MainPage.xaml.cs中 定位到如下注释部分:
C#
private void btnSaveRingtone_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to the save ringtone page
}
使用下面的代码替换掉注释部分:
C#
private void btnSaveRingtone_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/SaveRingtonePage.xaml",
UriKind.Relative));
}
60. 添加一个新的页面ComposeEmailPage 至 Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
61. 修改SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.ComposeEmailPage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
62. 为了简化设计过程,使用以下的代码替换掉整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource
AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Email"
Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1" >
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock Text="To:" Style="{StaticResource
TextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtTo" InputScope="EmailNameOrAddress" Margin="0"/>
<TextBlock Text="CC:" Style="{StaticResourceTextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtCc" InputScope="EmailNameOrAddress" Margin="0"/>
<TextBlock Text="BCC:" Style="{StaticResourceTextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtBcc"InputScope="EmailNameOrAddress" Margin="0"/>
<TextBlock Text="Subject:" Style="{StaticResourceTextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtSubject"Margin="0"/>
<TextBlock Text="Body:" Style="{StaticResourceTextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtBody" Margin="0"/>
<Button Content="Create Email" x:Name="btnCreateEmail"Click="btnCreateEmail_Click"/>
</StackPanel>
</Grid>
</Grid>
上述的标记描述语言代码使界面看起来像下面的样子:
图 12
发送Email页面
63. 在 ComposeEmailPage.xaml.cs中添加如下事件:
C#
private voidbtnCreateEmail_Click(object sender, RoutedEventArgs e)
{
}
64. 在 MainPage.xaml.cs. 页面中定位到如下的代码:
C#
private void btnComposeEmail_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to the email composition page
}
用下面的代码替换掉注释部分:
C#
private void btnComposeEmail_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Views/ComposeEmailPage.xaml",
UriKind.Relative));
}
65. 添加新的页面ShowMapPage 至 Views 文件夹.
注意为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
66. 修改 SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.ShowMapPage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
67. 为了简化设计过程,使用以下的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Show Map" Margin="9,-7,0,0" Style="{StaticResourcePhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1" Margin="0">
<StackPanel Grid.Row="0" Orientation="Vertical">
<RadioButton x:Name="radioLocation"Content="Center on location:" IsChecked="True"/>
<TextBox x:Name="txtLocation"IsEnabled="{Binding ElementName=radioLocation, Path=IsChecked}" Margin="0,0,0,10"/>
<RadioButton x:Name="radioCoordinate"Content="Center on coordinate:"/>
<Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Latitude:"Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Style="{StaticResource
TextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtLatitude"Grid.Row="0"
Grid.Column="1" IsEnabled="{Binding ElementName=radioCoordinate,
Path=IsChecked}" InputScope="Number"/>
<TextBlock Text="Longitude:"Grid.Row="1"
Grid.Column="0"VerticalAlignment="Center" Style="{StaticResource
TextBlockTitleMediumStyle}"/>
<TextBox x:Name="txtLongitude"Grid.Row="1" Grid.Column="1" IsEnabled="{Binding ElementName=radioCoordinate, Path=IsChecked}" InputScope="Number"/>
</Grid>
<TextBlock Text="Zoom level:"Style="{StaticResource TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtZoom"InputScope="Number"/>
<Button Content="Show Map" x:Name="btnShowMap" Click="btnShowMap_Click"/>
</StackPanel>
</Grid>
</Grid>
上述标记表述语言代码使界面呈现以下的样子:
图 13
显示地图页面
68. 在ShowMapPage.xaml.cs中添加如下的事件:
C#
private voidbtnShowMap_Click(object sender, RoutedEventArgs e)
{
}
69. 在 MainPage.xaml.cs. 定位到如下代码位置:
C#
private void btnShowMap_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the map viewing page
}
使用下面的代码替换掉注释部分:
C#
private void btnShowMap_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Views/ShowMapPage.xaml", UriKind.Relative));
}
70. 添加新的页面DirectionsPage 到Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
71. 修改SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.DirectionsPage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
72. 为了简化设计过程,使用以下的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Directions"Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1" >
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock Text="Origin:" Style="{StaticResourceTextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtOrigin" Margin="0"/>
<TextBlock Text="Destination:"Style="{StaticResource TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtDestination"Margin="0"/>
<Button Content="Get Directions" x:Name="btnGetDirections"Click="btnGetDirections_Click"/>
</StackPanel>
</Grid>
</Grid>
上述标记描述语言使界面看起来像这样:
图 14
Directions页面
73. 在DirectionsPage.xaml.cs中添加以下事件:
C#
private voidbtnGetDirections_Click(object sender, RoutedEventArgs e)
{
}
74. 在 MainPage.xaml.cs.中定位到如下注释部分:
C#
private void btnGetDirections_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the directions page
}
然后用下面的代码替换注释部分:
C#
private void btnGetDirections_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Views/DirectionsPage.xaml", UriKind.Relative));
}
75. 添加新的页面ShowMarketplacePage 到 Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
76. 修改SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.ShowMarketplacePage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
77. 为了简化设计过程,使用下面的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel containsthe name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Marketplace"
Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - placeadditional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<StackPanel Grid.Row="0" Orientation="Vertical">
<Button Content="Show Marketplace"
x:Name="btnShowMarketplace" Click="btnShowMarketplace_Click"/>
</StackPanel>
</Grid>
</Grid>
上述的标记描述语言使界面看起来像下面的样子:
图 15
显示Marketplace 页面
78. 在 ShowMarketplacePage.xaml.cs中添加以下事件:
C#
private voidbtnShowMarketplace_Click(object sender, RoutedEventArgs e)
{
}
79. 在 MainPage.xaml.cs.定位到以下注释部分:
C#
private void btnShowMarketplace_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the marketplace
}
用以下代码替换掉注释部分:
C#
private void btnShowMarketplace_Click (object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Views/ShowMarketplacePage.xaml",
UriKind.Relative));
}
80. 添加新的页面SearchMarketplacePage至Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
81. 修改 SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage x:Class="LaunchersAndChoosers.Views.SearchMarketplacePage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
82. 为了简化设计过程,使用以下代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Marketplace"Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock Text="Search Term:"Style="{StaticResource TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtSearchTerm"/>
<Button Content="Search Marketplace" x:Name="btnSearchMarketplace" Click="btnSearchMarketplace_Click"/>
</StackPanel>
</Grid>
</Grid>
上述标记描述语言使界面呈现以下效果:
图 16
搜索 Marketplace 页面
83. 在 SearchMarketplacePage.xaml.cs中添加以下事件:
C#
private voidbtnSearchMarketplace_Click(object sender,
RoutedEventArgs e)
{
}
84. 在MainPage.xaml.cs. 定位到以下注释部分:
C#
private void btnSearchMarketplace_Click(object sender,
RoutedEventArgs e)
{
//TODO - navigate to the marketplace search page
}
用下面的代码替换注释部分:
C#
private void btnSearchMarketplace_Click (object sender,
RoutedEventArgs e)
{
NavigationService.Navigate(new
Uri("/Views/SearchMarketplacePage.xaml",UriKind.Relative));
}
85. 添加新的文件MarketplaceDetailsPage 到Views 文件夹.
注意: 为了添加一个新的页面, 右键单击 Views 文件夹,从下拉菜单中选择 Add ,然后从Add 上下文菜单中选择New Item.
86. 修改SupportedOrientations 属性的值为PortraitOrLandscape.
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.MarketplaceDetailsPage"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
87. 为了简化设计过程,使用下面的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the applicationand page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource
AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Marketplace"
Margin="-3,-8,0,0" Style="{StaticResourcePhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<StackPanel Grid.Row="0" Orientation="Vertical">
<Button Content="ShowDetails"
x:Name="btnMarketplaceDetails" Click="btnMarketplaceDetails_Click"/>
</StackPanel>
</Grid>
</Grid>
上述的标记描述语言使界面呈现如下:
图 17
Marketplace详细页面
88. 在 MarketplaceDetailsPage.xaml.cs添加如下事件:
C#
private voidbtnMarketplaceDetails_Click(object sender,
RoutedEventArgs e)
{
}
89. 在 MainPage.xaml.cs中定位到如下注释部分:
C#
private void btnMarketplaceDetails_Click(object sender,
RoutedEventArgs e)
{
//TODO - navigate to the marketplace details page
}
用下面的代码替换掉注释部分:
C#
private void btnSearchMarketplace_Click (object sender,
RoutedEventArgs e)
{
NavigationService.Navigate(new
Uri("/Views/MarketplaceDetailsPage.xaml",UriKind.Relative));
}
90. 编译并运行程序,检查导航是否正确工作,并检查不同页面的软键盘格式.
任务 2 – 使用 Launchers
一个 launcher是一个API,它启动一个系统内置应用程序,通过这个内置应用程序用户可以完成一些任务,当任务完成时没有返回值. 其中一个例子是PhoneCallTask.应用程序可以提供给这个launcher一个电话号码和显示名称来启动电话程序. 当电话程序启动的时候,用户可以选择是否拨打电话。当用户关闭电话应用程序的时候,应用程序被重新激活,但是电话应用程序不返回任何数据。当应用程序启动一个launcher,它不会得到返回值.
1. 打开SavePhoneNumberPage.xaml.cs.
注意: 在本实验中使用正则表达式来验证用户输入.
2. 添加下面的代码到SavePhoneNumberPage 类:
C#
//Regex patterns provided by http://regexlib.com/
const string phoneNumberPattern = @"^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})(|-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$";
Note: The regular expression is providedby the “Regular Expression Library” site (http://regexlib.com).For more information about regular expressions refer to the MSDN documentation(http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx).
3. 添加下面的命名空间:
C#
using System.Text.RegularExpressions;
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
4. 重写 OnNavigatedFrom 和 OnNavigatedTo 来保存电话号码到页面状态,这样当应用程序从墓碑化激活之后能重新显示.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of SavePhoneNumberPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
State.Add(inputStateKey, txtInput.Text);
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of SavePhoneNumberPage\t ***");
if (State.ContainsKey(inputStateKey))
{
string input = (string)State[inputStateKey];
txtInput.Text = input;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
5. 添加下面的常量到SavePhoneNumberPage 类.
C#
const string inputStateKey = "input";
6. 添加 SavePhoneNumberTask 变量到SavePhoneNumberPage 类.
C#
SavePhoneNumberTask savePhoneNumberTask;
7. 在构造函数中添加下面高亮部分的代码初始化savePhoneNumberTask 变量 ,并输出调试信息.
C#
public SavePhoneNumberPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofSavePhoneNumberPage\t ***");
savePhoneNumberTask = new SavePhoneNumberTask();
savePhoneNumberTask.Completed+= new EventHandler<TaskEventArgs>(savePhoneNumberTask_Completed);
}
8. 添加下面的代码处理完成事件.
C#
voidsavePhoneNumberTask_Completed(object sender, TaskEventArgs e)
{
Debug.WriteLine("***\t In savePhoneNumberTask_Completed function ofSavePhoneNumberPage\t ***");
if (e.TaskResult == TaskResult.OK)
MessageBox.Show("Phone number saved successfully", "Success", MessageBoxButton.OK);
else if (e.TaskResult == TaskResult.Cancel)
MessageBox.Show("Phone number was not saved - operation wascancelled", "Contact notselected", MessageBoxButton.OK);
else
MessageBox.Show("Error while saving phone number:\n" +e.Error.Message, "Fail", MessageBoxButton.OK);
}
9. 使用正则表达式验证用户输入. 如果验证通过,使用SavePhoneNumberTask 来保存合法的电话号码. SavePhoneNumberTask 使应用程序可以启动联系人应用程序.使用它可以使用户保存一个电话号码至已有或者新建联系人.
C#
private void btnSavePhone_Click(object sender, RoutedEventArgse)
{
if (Regex.IsMatch(txtInput.Text,phoneNumberPattern, RegexOptions.IgnoreCase))
{
if (null !=savePhoneNumberTask)
{
savePhoneNumberTask.PhoneNumber = txtInput.Text;
savePhoneNumberTask.Show();
}
}
else
{
MessageBox.Show("Specifiedvalue is not a valid phone number\nValid phone number looks like thefollowing:\n1-(123)-123-1234, 123 123 1234, 1-800-ALPHNUM", "Invalid Input", MessageBoxButton.OK);
}
}
10. 按 F5 编译并运行应用程序.
11. 导航到 Save Phone Number 页面并输入一个合法的电话号码.
12. 点击Save Phone Number 启动Launcher.
13. 使用标准的 Windows® Phone 7 界面添加一个电话号码至已有或新增联系人:
图 18
添加一个电话号码至已有或新增联系人
14. 可选的, 可以给联系人一个名称.
图 19
新增联系人信息
15. 保存联系人并按下Back ():
图 20
显示返回信息
注意: 输入的电话号码显示在输入框,尽管应用程序在调用PhoneSaveTask 中被放置到后台,分析调试输出信息可以更好的理解这一点.
16. 重复以上步骤添加一个新联系人.
注意: 模拟器只会在运行期间保存联系人数据. 在这些步骤中请不要关闭模拟器,以保证在本实验后面能看到联系人数据
17. 按 SHIFT+F5 停止调试并返回编辑模式.
18. 打开 SaveEmailAddressPage.xaml.cs.
19. 使用以下的正则表达式验证用户输入. 添加下面的代码到aveEmailAddressPage 类中:
C#
//Regex patterns provided by http://regexlib.com/
const string emailAddressPattern = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
20. 添加下面的引用声明:
C#
using System.Text.RegularExpressions;
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
21. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法用来保存Email地址到页面状态,这样当应用程序从墓碑化激活后能重新显示.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of SaveEmailAddressPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
State.Add(inputStateKey,txtInput.Text);
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of SaveEmailAddressPage\t ***");
if (State.ContainsKey(inputStateKey))
{
string input = (string)State[inputStateKey];
txtInput.Text= input;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
22. 添加下面的常量到SaveEmailAddressPage 类.
C#
const string inputStateKey = "input";
23. 添加一个 SaveEmailAddressTask 变量到 SaveEmailAddressPage 类.
C#
SaveEmailAddressTask saveEmailAddressTask;
24. 在构造函数中用下面高亮部分的代码来初始化saveEmailAddressTask 变量.
C#
public SaveEmailAddressPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofSaveEmailAddressPage\t ***");
saveEmailAddressTask = new SaveEmailAddressTask();
saveEmailAddressTask.Completed+= new EventHandler<TaskEventArgs>(saveEmailAddressTask_Completed);
}
25. 添加完成事件.
C#
void saveEmailAddressTask_Completed(objectsender, TaskEventArgs e)
{
Debug.WriteLine("***\t InsaveEmailAddressTask_Completed function of SaveEmailAddressPage\t ***");
if (e.TaskResult == TaskResult.OK)
MessageBox.Show("Emailaddress saved successfully", "Success",MessageBoxButton.OK);
else if (e.TaskResult== TaskResult.Cancel)
MessageBox.Show("Emailaddress was not saved - operation was cancelled", "Contact not selected", MessageBoxButton.OK);
else
MessageBox.Show("Errorwhile saving email address:\n" + e.Error.Message, "Fail", MessageBoxButton.OK);
}
26. 使用正则表达式验证用户输入. 如果验证通过, 使用SaveEmailAddressTask来保存合法的邮件地址,SaveEmailAddressTask 使应用程序可以启动内置联系人应用程序.这样可以使用户保存邮件地址到已有或新增联系人.
C#
private void btnSaveEmail_Click(object sender, RoutedEventArgse)
{
if (Regex.IsMatch(txtInput.Text, emailAddressPattern, RegexOptions.IgnoreCase))
{
if (null !=saveEmailAddressTask)
{
saveEmailAddressTask.Email = txtInput.Text;
saveEmailAddressTask.Show();
}
}
else
{
MessageBox.Show("Specifiedvalue is not a valid email address\nValid email address looks like thefollowing:\[email protected], [email protected]", "Invalid Input", MessageBoxButton.OK);
}
}
27. 按 F5 编译和运行应用程序.
28. 导航到 Save Email 页面,并输入一个合法的邮件地址.
29. 点击 Save Email Address启动Launcher.
30. 使用标准的 Windows® Phone 7 界面添加一个邮件地址至已有或新增联系人:
图 21
添加新的电子邮件至已有或新增联系人
31. 保存联系人并单击Back ():
图 22
Launcherreturn notification
32. 按 SHIFT+F5 停止调试并返回编辑模式.
33. 打开 SearchTaskPage.xaml.cs.
34. 添加下面的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
35. 重写OnNavigatedFrom 和 OnNavigatedTo 方法保存搜索关键字到页面状态,这样当应用程序从墓碑化激活之后可以重新显示:
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of SearchTaskPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
State.Add(inputStateKey, txtInput.Text);
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of SearchTaskPage\t ***");
if (State.ContainsKey(inputStateKey))
{
string input = (string)State[inputStateKey];
txtInput.Text= input;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
36. 添加下面的常数到SearchTaskPage 类:
C#
const string inputStateKey = "input";
37. 在构造函数中用下面高亮部分的代码创建调试信息:
C#
public SearchTaskPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofSearchTaskPage\t ***");
}
38. 为了执行搜索功能,本实验使用SearchTask 来启动Web搜索应用程序,找到btnSearch_Click 事件并添加以下代码:
C#
private void btnSearch_Click(object sender, RoutedEventArgse)
{
SearchTask searchTask = new SearchTask();
searchTask.SearchQuery =txtInput.Text;
searchTask.Show();
}
39. 编译并运行应用程序.
40. 导航到搜索页面并输入搜索关键字:
图 23
搜索页面
41. 单击 Search Everywhere. 如果可能,第一次搜索会显示以下信息:
图 24
允许应用程序使用地理信息
注意: 为了优化搜索结果,搜索引擎可以使用手机或模拟器提供的地理信息
42. 单击 Allow允许使用地理信息. 模拟器连接Web并返回搜索结果:
图 25
Web搜索结果
43. 单击Back ()返回应用程序.
44. 按 SHIFT+F5 停止调试并返回编辑模式.
45. 打开 WebSearchPage.xaml.cs.
46. 添加下面的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
47. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法以保存搜索数据至页面状态,当应用程序从墓碑化激活的时候可以重新显示这些数据.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of WebSearchPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
State.Add(inputStateKey, txtInput.Text);
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of WebSearchPage\t ***");
if (State.ContainsKey(inputStateKey))
{
string input = (string)State[inputStateKey];
txtInput.Text= input;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
48. 添加下面的常量到WebSearchPage.
C#
const string inputStateKey = "input";
49. 在构造函数中添加下面高亮部分的代码以输出调试信息.
C#
public WebSearchPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofWebSearchPage\t ***");
}
50. Silverlight 有一个WebBrowser 控件,可以在应用程序中和其他控件一样使用. 同时Windows Phone 还有一个 WebBrowser 允许在应用程序中直接启动IE浏览器。本实验使用 WebBrowserTask..找到btnGo_Click 事件添加以下代码:
C#
private void btnGo_Click(object sender, RoutedEventArgse)
{
WebBrowserTask webBrowserTask = new WebBrowserTask();
conststring url = "http://m.bing.com/search?q={0}&a=results";
webBrowserTask.URL = string.Format(url, txtInput.Text);
webBrowserTask.Show();
}
51. 按 F5 编译并运行应用程序.
52. 导航到搜索页面并输入搜索关键字:
图 26
浏览Web页面
启动IE浏览器并导航到Bing页面:
图 27
Windows®Phone 7.1 IE
注意: 在 Windows® Phone 7.0 上浏览器有不同的外观.
53. 按 SHIFT+F5 停止调试返回到编辑模式.
54. 打开 VideoPlayerPage.xaml.cs.
55. 添加下面的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
56. 重写OnNavigatedFrom 和 OnNavigatedTo 在应用程序墓碑化的时候输出调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of VideoPlayerPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of VideoPlayerPage\t ***");
base.OnNavigatedTo(e);
}
57. 从本实验的Source\Assets文件夹中,添加已经存在的视频文件到Media 文件夹.
图 28
添加一个已经存在的视频文件
58. 在 Add Existing Item 对话框中浏览到 Assets文件夹, 选择视频文件, 从 Add 按钮的下拉菜单选择 Add As Link.
图 29
选择视频文件
59. 确保视频文件设置为Content 资源. 为了检查这个, 在 Solution Explorer中单击添加的文件并按F4显示属性面板.
图 30
检查添加视频文件的 Build Action
60. 在构造函数中添加下高亮部分的代码以输入调试信息.
C#
public VideoPlayerPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofVideoPlayerPage\t ***");
}
61. 添加点击处理事件,该方法会使用MediaPlayerLauncher, 它启动媒体播放器播放视频。添加下面的代码到类中:
C#
private voidbtnPlayVideo_Click(object sender, RoutedEventArgs e)
{
MediaPlayerLaunchermediaPlayerLauncher =
new MediaPlayerLauncher();
mediaPlayerLauncher.Location =
MediaLocationType.Install; //means is aresource of the app, otherwise it will try to resolve it in Data(IsolatedStorage) for application
mediaPlayerLauncher.Media = new Uri("Media/Bear.wmv", UriKind.Relative);
mediaPlayerLauncher.Show();
}
62. 按 F5 编译并运行.
63. 导航到视频播放页面并播放视频.
图 31
播放视频
64. 按 SHIFT+F5 停止调试并返回到编辑模式.
65. 打开 SaveRingtonePage.xaml.cs.
66. 添加下面的引用声明:
C#
using System.IO.IsolatedStorage;
using System.IO;
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
67. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法以使应用程序在墓碑化的时候输出调试信息.
C#
protected overridevoid OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of SaveRingtonePage\t ***");
base.OnNavigatedFrom(e);
}
protected overridevoid OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of SaveRingtonePage\t ***");
base.OnNavigatedTo(e);
}
68. 添加一个音频文件用来作为铃声. 重复 步骤 57-59两次 , 但是取代的添加 “Bear.wmv” 和 “Ringtone.mp3”文件.
69. 在构造函数中添加下面高亮部分的代码以输出调试信息,并把我们要使用的新的铃声放置到独立存储中.
C#
public ComposeEmailPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofSaveRingtonePage\t ***");
PlaceAssetInIsolatedStorage();
}
70. 添加下面的方法用来将铃声保存到独立存储
C#
private staticvoid PlaceAssetInIsolatedStorage()
{
using (IsolatedStorageFileiso =
IsolatedStorageFile.GetUserStoreForApplication())
{
Stream str = Application.GetResourceStream(new
Uri("Media/Ring.mp3",UriKind.Relative)).Stream;
IsolatedStorageFileStream outFile =iso.CreateFile("Ring.mp3");
outFile.Write(ReadToEnd(str), 0, (int)str.Length);
str.Close();
outFile.Close();
}
}
private staticbyte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = stream.Position;
stream.Position= 0;
try
{
byte[] readBuffer = newbyte[4096];
int totalBytesRead = 0;
intbytesRead;
while ((bytesRead = stream.Read(readBuffer,totalBytesRead,
readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
intnextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = newbyte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp,0,
readBuffer.Length);
Buffer.SetByte(temp,totalBytesRead,
(byte)nextByte);
readBuffer = temp; totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer= new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0,totalBytesRead);
}
return buffer;
}
finally
{
stream.Position = originalPosition;
}
}
71. 为了让用户将某个铃声应用到联系人,我们会使用SaveRingtoneTask. 找到btnSaveRingtone_Click 并添加下面的代码:
C#
private void btnSaveRingtone_Click(object sender, RoutedEventArgse)
{
SaveRingtoneTask ringtoneTask = new SaveRingtoneTask();
ringtoneTask.Source = new Uri("isostore:/Ring.mp3", UriKind.Absolute);
ringtoneTask.Show();
}
72. 按 F5 编译并运行应用程序.
73. 导航到 “Save Ringtone” 页面,并按下屏幕上唯一的按钮:
图 32
保存铃声页面
74. 按下 “Save Ringtone”按钮会转换到系统内置的铃音保存界面,允许指定一个文件名称并设置为当前铃音:
图 33
内置铃音保存界面
75. 按 SHIFT+F5 停止调试,并回到编辑模式.
76. 打开 ComposeEmailPage.xaml.cs.
77. 添加下面的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
78. 添加下面的类. 我们会用它来保存用户输入的数据:
C#
public classEmailInputData
{
public string To { get; set; }
public string Cc { get; set; }
public string Bcc { get; set; }
public string Subject{ get; set; }
public string Body { get; set; }
}
79. 重写OnNavigatedFrom 和 OnNavigatedTo 方法以保存Email数据到页面状态,以使应用程序在被墓碑化时能重新显示.
C#
protected overridevoid OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of ComposeEmailPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
EmailInputData inputData = new EmailInputData
{
To =txtTo.Text,
Cc =txtCc.Text,
Bcc =txtBcc.Text,
Subject =txtSubject.Text,
Body =txtBody.Text
};
State.Add(inputStateKey,inputData);
base.OnNavigatedFrom(e);
}
protected overridevoid OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of ComposeEmailPage\t ***");
if (State.ContainsKey(inputStateKey))
{
EmailInputData inputData = (EmailInputData)State[inputStateKey];
txtTo.Text= inputData.To;
txtCc.Text= inputData.Cc;
txtBcc.Text= inputData.Bcc;
txtSubject.Text = inputData.Subject;
txtBody.Text = inputData.Body;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
80. 添加下面的常量到ComposeEmailPage 类.
C#
const string inputStateKey = "input";
81. 在构造函数中添加下面高亮部分的代码以输出调试信息.
C#
public ComposeEmailPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofComposeEmailPage\t ***");
}
82. 为了能发送电子邮件,我们会使用到EmailComposeTask. EmailComposeTask 启动内置的电子邮件发送程序,并用用户提供的数据作为邮件内容. 找到btnCreateEmail_Click 事件并添加下面的代码:
C#
private void btnCreateEmail_Click(object sender, RoutedEventArgse)
{
if (Microsoft.Devices.Environment.DeviceType ==
Microsoft.Devices.DeviceType.Emulator)
{
MessageBox.Show("Thisoperation is not supported in the emulator. Please use an actual device.");
return;
}
EmailComposeTask composeTask = new EmailComposeTask();
composeTask.To= txtTo.Text;
composeTask.Cc= txtCc.Text;
composeTask.Bcc= txtBcc.Text;
composeTask.Subject = txtSubject.Text;
composeTask.Body = txtBody.Text;
composeTask.Show();
}
注意: 注意我们在方法的开头部分添加一段代码阻止此任务在Windows® Phone 7 模拟器上运行. 我们这样做是因为这个任务必须通过一个Email账户才能正确运行,但是在模拟器上不能设置Email账户.在后续的步骤中请确保你的设备上正确设置了Email账户以使任务正确运行.
83. 按 F5 编译并运行应用程序.
84. 导航到发送邮件页面,并填充相应的字段:
图 34
发送一封邮件
85. 按下 “Create Email” 按钮将会打开系统内置的Email发送器,呈现一个带有提供数据的Email界面.
86. 按下 SHIFT+F5 停止调试并返回到编辑模式.
87. 打开 ShowMapPage.xaml.cs.
88. 添加如下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
using System.Device.Location;
89. 用以下的代码添加一个类,我们会用它来存储用户输入的数据:
C#
public classMapInputData
{
public boolCenterOnCoordinate { get; set; }
public stringLongitude { get; set;}
public stringLatitude { get; set;}
public stringLocation { get; set;}
public stringZoomLevel { get; set;}
}
90. 重写OnNavigatedFrom 和 OnNavigatedTo 方法以保存地图数据至页面状态,这样当应用程序从墓碑化状态恢复时可以显示这些数据.
C#
protected overridevoid OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of ShowMapPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
MapInputData inputData = newMapInputData
{
CenterOnCoordinate = radioCoordinate.IsChecked.Value,
Longitude =txtLongitude.Text,
Latitude = txtLatitude.Text,
Location =txtLocation.Text,
ZoomLevel =txtZoom.Text
};
State.Add(inputStateKey, inputData);
base.OnNavigatedFrom(e);
}
protected overridevoid OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of ShowMapPage\t ***");
if (State.ContainsKey(inputStateKey))
{
MapInputData inputData = (MapInputData)State[inputStateKey];
if (inputData.CenterOnCoordinate)
{
radioCoordinate.IsChecked = true;
}
else
{
radioLocation.IsChecked = true;
}
txtLocation.Text = inputData.Location;
txtLatitude.Text = inputData.Latitude;
txtLongitude.Text = inputData.Longitude;
txtZoom.Text = inputData.ZoomLevel;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
91. 添加如下变量到ShowMapPage 类.
C#
const string inputStateKey = "input";
92. 在构造函数中添加以下高亮部分的代码以输入调试信息.
C#
public ShowMapPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofShowMapPage\t ***");
}
93. 为了使用户可以查看地图,我们将会使用BingMapsTask. 它启动内置的地图应用程序,用用户提供的数据初始化地图的位置,找到 btnShowMap_Click 事件并添加以下的代码:
C#
private void btnShowMap_Click(object sender, RoutedEventArgse)
{
BingMapsTask mapTask = new BingMapsTask();
if (radioCoordinate.IsChecked.Value)
{
double longitude;
double latitude;
if (!double.TryParse(txtLongitude.Text,out longitude) ||
Math.Abs(longitude) > 180)
{
MessageBox.Show("Pleasesupply a longitude between -180 and 180");
return;
}
if (!double.TryParse(txtLatitude.Text,out latitude) ||
Math.Abs(latitude) > 90)
{
MessageBox.Show("Pleasesupply a longitude between -90 and 90");
return;
}
mapTask.Center = new GeoCoordinate(latitude, longitude);
}
else
{
mapTask.SearchTerm = txtLocation.Text;
if (String.IsNullOrEmpty(mapTask.SearchTerm))
{
MessageBox.Show("Pleaseprovide a location.");
return;
}
}
int zoomLevel;
if (!int.TryParse(txtZoom.Text,out zoomLevel) || zoomLevel < 1 ||
zoomLevel> 19)
{
MessageBox.Show("Pleasesupply a zoom level which is a whole number between 1 and 19.");
return;
}
mapTask.ZoomLevel = zoomLevel;
mapTask.Show();
}
94. 按 F5 编译并运行应用程序.
95. 导航到展示地图的页面,并使用搜索框或者条件选择一个地点:
图 35
选择地图地点
96. 按下 “Show Map” 按钮将会导航到系统内置的地图应用程序,以提供的地点为中心位置:
图 36
地图以指定的地点为中心
注意: 如果你没有设置过允许使用地理信息,你会收到类似的提示信息.
97. 按 SHIFT+F5 停止调试并返回到编辑模式.
98. 打开 DirectionsPage.xaml.cs.
99. 添加下面的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
100. 添加如下的类,用来存储用户输入的数据:
C#
public classMapInputData
{
public boolCenterOnCoordinate { get; set; }
public stringLongitude { get; set;}
public stringLatitude { get; set;}
public stringLocation { get; set;}
public stringZoomLevel { get; set;}
}
101. 重写OnNavigatedFrom 和 OnNavigatedTo 方法用来保存方向数据在页面状态,这样应用程序在墓碑化之后能够重新显示
C#
protected overridevoid OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of DirectionsPage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
DirectionsInputData inputData = new DirectionsInputData
{
Origin =txtOrigin.Text,
Destination= txtDestination.Text
};
State.Add(inputStateKey, inputData);
base.OnNavigatedFrom(e);
}
protected overridevoid OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of DirectionsPage\t ***");
if (State.ContainsKey(inputStateKey))
{
DirectionsInputData inputData =
(DirectionsInputData)State[inputStateKey];
txtOrigin.Text = inputData.Origin;
txtDestination.Text= inputData.Destination;
State.Remove(inputStateKey);
}
base.OnNavigatedTo(e);
}
102. 添加如下的常量到DirectionsPage 类.
C#
const string inputStateKey = "input";
103. 在构造函数中添加以下高亮部分的代码以输出调试信息.
C#
public ShowMapPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofDirectionsPage\t ***");
}
104. 为了让用户查看方向,我们将会使用ingMapsDirectionsTask.它启动内置地图应用程序,找到 btnGetDirections_Click 事件并添加以下的代码:
C#
private void btnGetDirections_Click(object sender, RoutedEventArgse)
{
BingMapsDirectionsTask directionsTask =
new BingMapsDirectionsTask();
if (String.IsNullOrEmpty(txtOrigin.Text))
{
MessageBox.Show("Pleasesupply an origin.");
return;
}
if (String.IsNullOrEmpty(txtDestination.Text))
{
MessageBox.Show("Pleasesupply a destination.");
return;
}
directionsTask.Start = new LabeledMapLocation(txtOrigin.Text, null);
directionsTask.End = new LabeledMapLocation(txtDestination.Text,
null);
directionsTask.Show();
}
105. 按 F5 编译并运行应用程序.
106. 导航到方向页面,并选择你希望显示方向的两个地点:
Figure 37
Selectingorigin and destination
107. 按下 “Get Directions” 按钮将会启动系统内置地图应用程序,显示相关的方向:
图 38
显示指定地点之间的方向
108. 按 SHIFT+F5 停止调试并返回到编辑模式.
109. 打开 ShowMarketplacePage.xaml.cs.
110. 添加以下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
111. 重写OnNavigatedFrom 和 OnNavigatedTo 方法在应用程序墓碑化的时候输出调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of ShowMarketplacePage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of ShowMarketplacePage\t ***");
base.OnNavigatedTo(e);
}
112. 在构造函数中添加以下高亮部分的代码以输出调试信息.
C#
public VideoPlayerPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofShowMarketplacePage\t ***");
}
113. 为了让用户可以查看 marketplace,我们将会使用MarketplaceHubTask. 它启动系统内置marketplace 应用程序. 找到btnShowMarketplace_Click 事件并添加以下代码:
C#
private voidbtnShowMarketplace_Click(object sender, RoutedEventArgs e)
{
MarketplaceHubTask marketplaceTask = new MarketplaceHubTask();
marketplaceTask.Show();
}
114. 按 F5 编译并运行程序.
115. 导航到显示 marketplace 的页面,并按下按钮前往marketplace 中心.
图 39
显示 marketplace的页面
116. 按下 SHIFT+F5 停止调试并返回到编辑模式.
117. 打开 SeachMarketplacePage.xaml.cs.
118. 添加以下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
119. 重写OnNavigatedFrom 和 OnNavigatedTo 方法保存搜索条件到页面状态,这样当墓碑化后可以重新显示.
C#
protected overridevoid OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of SearchMarketplacePage\t ***");
if (State.ContainsKey(inputStateKey))
State.Remove(inputStateKey);
State.Add(inputStateKey, txtSearchTerm.Text);
base.OnNavigatedFrom(e);
}
protected overridevoid OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of SearchMarketplacePage\t ***");
if (State.ContainsKey(inputStateKey))
{
txtSearchTerm.Text = (String)State[inputStateKey];
}
base.OnNavigatedTo(e);
}
120. 添加以下常量到SearchMarketplacePage 类.
C#
const string inputStateKey = "input";
121. 在构造函数中添加以下高亮部分的代码以输出调试信息.
C#
public ShowMapPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor ofSearchMarketplacePage\t ***");
}
122. 为了让用户搜索marketplace,我们将会使用MarketplaceSearchTask. enables an 它启动系统内置的marketplace应用程序, 并仅仅显示匹配的应用程序内容,找到btnSearchMarketplace_Click 事件并添加以下代码:
C#
private void btnSearchMarketplace_Click(object sender,
RoutedEventArgs e)
{
MarketplaceSearchTask marketplaceTask = new MarketplaceSearchTask();
marketplaceTask.SearchTerms = txtSearchTerm.Text;
marketplaceTask.Show();
}
123. 按 F5 编译并运行应用程序.
124. 导航到marketplace 搜索页面,并输入一个搜索条件:
图 40
搜索 marketplace
125. 按下 “Search Marketplace” 按钮将会启动内置的marketplace应用程序,并用提供的条件搜索应用程序:
图 41
匹配搜索条件的内容
126. 按下 SHIFT+F5 停止调试并返回到编辑模式.
127. 打开 MarketplaceDetailsPage.xaml.cs.
128. 添加以下引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
129. 重写OnNavigatedFrom 和 OnNavigatedTo 方法,当应用程序墓碑化的时候输出调试信息
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of MarketplaceDetailsPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of MarketplaceDetailsPage\t ***");
base.OnNavigatedTo(e);
}
130. 在构造函数中添加下面高亮部分的代码以显示调试信息.
C#
public VideoPlayerPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor of MarketplaceDetailsPage\t***");
}
131. 为了让用户查看一个 marketplace应用程序的详细页面我们将会用到 MarketplaceDetailTask. 它启动系统内置的marketplace 应用程序并显示一个给定应用程序的详细页面. 找到 btnMarketplaceDetails_Click 事件并添加以下代码:
C#
private voidbtnMarketplaceDetails_Click(object sender,
RoutedEventArgs e)
{
MarketplaceDetailTask marketplaceTask = new MarketplaceDetailTask();
marketplaceTask.ContentIdentifier = "35323b0f-84d8-df11-a844-00237de2db9e";
marketplaceTask.Show();
}
132. 按 F5 编译并运行应用程序.
133. 导航到marketplace details 页面,并按下按钮显示 “The Harvest™”应用程序的marketplace详细页面.
图 42
显示 一个marketplace 应用程序的详细页面
注意: 如果设备连接到计算机,Marketplace 以及许多相关的操作都不能进行,即时在调试的时候也不行.
134. 按下 SHIFT+F5 停止调试并返回到编辑模式.
这个步骤包括以下练习.
注意: 这个练习的解决方案可以在以下文件夹找到:Source\Ex1-Launchers\End.
练习 2: Choosers介绍和使用
一个 chooser是一个应用程序接口,通过它可以启动一个内置应用程序来帮助用户完成一些任务,当任务完成之后会返回某种类型的数据给调用应用程序。例如phone chooser 启动 "contact people" 的界面搜索一个特定的联系人,当完成的时候请求的联系人信息会被返回。另一个例子是 PhotoChooserTask.它可以启动Photo Chooser 应用程序使用户可以选择一张照片,用户可以选择取消,当选择完成之后,调用它的应用程序被重新激活,并返回数据给调用应用程序。 返回的数据包含一个值指示用户是否完成了任务,如果用户完成了任务,返回结果包含相关数据,比如包含选中照片文件的IO文件流.
任务 1 – 使用 Choosers
不像前面的练习,我们已经添加了搜索的页面,剩下的仅仅是实现它的逻辑。这里我们会添加每一个页面并且立即实现它的逻辑.
1. 打开 MicrosoftVisual Studio 2010 Express for Windows Phone :Start | All Programs | MicrosoftVisual Studio 2010 Express | Microsoft Visual Studio 2010 Express for WindowsPhone.
Visual Studio 2010: 打开 Visual Studio 2010 : Start | All Programs |Microsoft Visual Studio 2010.
2. 从本实验的文件夹打开起始解决方案:Source\Ex2-Choosers\Begin.
注意: 你也可以在前一个练习的基础上继续本实验.
3. 在 Views 文件夹添加一个页面命名为 MakePhoneCallPage.
注意: 为了添加一个新页面, 右键 点击Views 文件夹, 从下拉菜单中选择 Add 然后从下拉菜单中选择New Item.
4. 在我们刚创建的页面找到PhoneApplicationPage 元素.
5. 修改 SupportedOrientations 属性的值为PortraitOrLandscape:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.MakePhoneCallPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
6. 为了简化设计过程,使用下面的代码整个替换 LayoutRoot 元素:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanelcontains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource AppName}" Style="{StaticResourcePhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="PhoneCall"Margin="-3,-8,0,0" Style="{StaticResourcePhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<StackPanel Orientation="Vertical" Grid.Row="0">
<Button x:Name="btnMakePhoneCall" Content="MakeCall"Margin="0,5" Click="btnMakePhoneCall_Click"/>
</StackPanel>
</Grid>
</Grid>
7. 打开 MakePhoneCallPage.xaml.cs.
8. 添加 btnMakePhoneCall_Click事件到MakePhoneCallPage.xaml.cs 的末尾.
C#
private void btnMakePhoneCall_Click(object sender, RoutedEventArgse)
{
}
9. 打开 MainPage.xaml.cs 并找到以下注释部分:
C#
private void btnMakePhoneCall_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to make phone call page
}
10. 用以下高亮部分的代码替换掉注释部分:
C#
private void btnMakePhoneCall_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/MakePhoneCallPage.xaml", UriKind.Relative));
}
11. 打开 MakePhoneCallPage.xaml.cs.
12. 添加以下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
13. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法在应用程序墓碑化的时候输出调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of MakePhoneCallPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of MakePhoneCallPage\t ***");
base.OnNavigatedTo(e);
}
在这个页面中,我们会拨打一个前面练习中添加的联系人,为了获取联系人的电话号码号码,我们会使用 PhoneNumberChooserTask 类. 它启动联系人应用程序来获得一个用户选择的联系人的电话号码. 这个 chooser是异步的,因此必须在启动它之前订阅 “Completed” 事件. 当这个chooser返回一个电话号码时,使用 PhoneCallTask 来拨打选中的电话号码.
14. 添加以下的变量:
C#
PhoneNumberChooserTask phoneNumberChooserTask;
15. 在构造函数中添加以下高亮部分的代码:
C#
public MakePhoneCallPage()
{
InitializeComponent();
Debug.WriteLine("***\t Inconstructor of MakePhoneCallPage\t ***");
phoneNumberChooserTask = new PhoneNumberChooserTask();
phoneNumberChooserTask.Completed+= new EventHandler<PhoneNumberResult>(phoneNumberChooserTask_Completed);
}
16. 使用以下代码添加一个完成事件phoneNumberChooserTask_Completed 来处理一些逻辑:
C#
void phoneNumberChooserTask_Completed(object sender,
PhoneNumberResult e)
{
string debugMsg = string.Format(
"***\t In phoneNumberChooserTask_Completed function ofMakePhoneCallPage, phone number returned: {0}, for contact: {1}\t ***",
e.PhoneNumber, e.DisplayName);
Debug.WriteLine(debugMsg);
if (e.TaskResult == TaskResult.OK)
{
PhoneCallTask phoneCallTask = new PhoneCallTask();
phoneCallTask.PhoneNumber =e.PhoneNumber;
phoneCallTask.Show();
}
else if(e.TaskResult == TaskResult.Cancel)
MessageBox.Show("Cannot make a phone call without a phone number", "Number not selected", MessageBoxButton.OK);
else
MessageBox.Show("Error getting phone number:\n" +e.Error.Message, "Fail", MessageBoxButton.OK);
}
17. 添加以下事件btnMakePhoneCall_Click :
C#
private void btnMakePhoneCall_Click(object sender, RoutedEventArgse)
{
phoneNumberChooserTask.Show();
}
18. 按 F5 编译并运行程序.
19. 导航到 “Make a Phone Call” 页面并 单击 Make Call:
图 43
拨打电话
20. 选择联系人:
图 44
选择一个联系人
21. 如果一个联系人有多个电话号码,会有一个额外的选择页面. 在本示例中,选择其中一个电话号码。如果此联系人只有一个电话号码,选择联系人及完成号码的选择.
图 45
可选的号码选择步骤
22. 单击 call 拨打电话:
图 46
拨打电话
23. 单击 end 返回拨打电话的页面:
图 47
正在通话屏幕
24. 按 SHIFT+F5 停止调试并返回编辑模式.
25. 在 Views 文件夹添加另外一个页面命名为SendSMSPage.
注意: 为了添加一个新页面, 右键 点击Views 文件夹, 从下拉菜单中选择 Add 然后从下拉菜单中选择New Item.
26. 找到PhoneApplicationPage 元素.
27. 修改SupportedOrientations 属性的值为PortraitOrLandscape:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.SendSMSPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
28. 为了简化设计过程,使用以下代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Send SMS"
Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical"Grid.Row="0">
<TextBlock Text="Message:" Style="{StaticResource
TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtInput"InputScope="Chat"/>
</StackPanel>
<StackPanel Orientation="Vertical"Grid.Row="2">
<Button x:Name="btnSendSMS" Content="Send SMS"
Margin="0,5" Click="btnSendSMS_Click"/>
</StackPanel>
</Grid>
</Grid>
29. 打开 SendSMSPage.xaml.cs.
30. 添加 btnSendSMS_Click事件到 SendSMSPage.xaml.cs 代码中.
C#
private void btnSendSMS_Click(object sender, RoutedEventArgse)
{
}
31. 打开 MainPage.xaml.cs 并且找到以下注释部分:
C#
private void btnSendSMS_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to send SMS page
}
32. 使用以下高亮部分代码替换掉注释部分:
C#
private void btnSendSMS_Click(objectsender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Views/SendSMSPage.xaml", UriKind.Relative));
}
33. 打开SendSMSPage.xaml.cs.
34. 添加以下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
35. 重写OnNavigatedFrom 和 OnNavigatedTo 方法在应用程序墓碑化的时候输出调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of SendSMSPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of SendSMSPage\t ***");
base.OnNavigatedTo(e);
}
这个练习使用户可以发送短信息到前面练习中添加的其中一个联系人。跟前一个页面一样,这个页面使用PhoneNumberChooserTask 来选择电话号码. 然后使用SmsComposeTask来启动发送短信息的应用程序并发送短信到指定的联系人.
36. 添加下面的变量到类中:
C#
PhoneNumberChooserTask phoneNumberChooserTask;
37. 在构造函数中添加以下高亮部分的代码:
C#
public UsePhoneNumberPage()
{
InitializeComponent();
Debug.WriteLine("***\t Inconstructor of SendSMSPage\t ***");
phoneNumberChooserTask = new PhoneNumberChooserTask();
phoneNumberChooserTask.Completed += new EventHandler<PhoneNumberResult>(phoneNumberChooserTask_Completed);
}
38. 添加 phoneNumberChooserTask_Completed 事件来处理相关逻辑:
C#
void phoneNumberChooserTask_Completed(object sender,
PhoneNumberResult e)
{
string debugMsg = string.Format(
"***\t In phoneNumberChooserTask_Completed function of SendSMSPage,phone number returned: {0}, for contact: {1}\t ***",
e.PhoneNumber, e.DisplayName);
Debug.WriteLine(debugMsg);
if (e.TaskResult == TaskResult.OK)
{
SmsComposeTasksmsComposeTask = new SmsComposeTask();
if(!string.IsNullOrEmpty(txtInput.Text))
smsComposeTask.Body = txtInput.Text;
smsComposeTask.To =e.PhoneNumber;
smsComposeTask.Show();
}
else if(e.TaskResult == TaskResult.Cancel)
MessageBox.Show("Cannot send SMS without a phone number","Number not selected", MessageBoxButton.OK);
else
MessageBox.Show("Error getting phone number:\n" + e.Error.Message,"Fail", MessageBoxButton.OK);
}
39. 添加 btnSendSMS_Click 事件:
C#
private void btnSendSMS_Click(object sender, RoutedEventArgse)
{
phoneNumberChooserTask.Show();
}
40. 按 F5 编译并运行应用程序.
41. 导航到 “Send SMS” 页面,输入一条信息并单击Send SMS:
图 48
发送信息
42. 选择联系人.
图 49
选择一个联系人
43. 如果一个联系人有多个电话号码,会有一个额外的选择步骤,在本示例中我们选择其中一个电话号码. 如果只有一个电话号码,选择联系人就完成了电话号码的选择.
图 50
可选的选择电话号码的步骤
44. 如果需要可以修改前面输入的短信内容,然后单击 Send ():
图 51
发送短信息
45. 按 Back ().
46. 按 SHIFT+F5 停止调试并返回编辑模式.
注意: 接下来得步骤演示发送电子邮件到一个联系人. 记住我们前面提到的,此功能在Windows®Phone 模拟器中不可用.
47. 在 Views 文件夹下添加另外的页面命名为UseEmailAddressPage.
注意: 为了添加一个新页面, 右键 点击Views 文件夹, 从下拉菜单中选择 Add 然后从下拉菜单中选择New Item.
48. 定位到PhoneApplicationPage 元素.
49. 修改SupportedOrientations 属性的值为PortraitOrLandscape:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.UseEmailAddressPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
50. 为了简化设计过程,使用以下的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanelcontains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource AppName}" Style="{StaticResourcePhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="EmailAddress"Margin="-3,-8,0,0" Style="{StaticResourcePhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<StackPanel Orientation="Vertical" Grid.Row="0">
<Button x:Name="btnSendEmail" Content="SendEmail"Margin="0,5" Click="btnSendEmail_Click"/>
</StackPanel>
</Grid>
</Grid>
51. 打开 UseEmailAddressPage.xaml.cs.
52. 添加 btnSendEmail_Click事件到UseEmailAddressPage.xaml.cs 文件.
C#
private void btnSendEmail_Click(object sender, RoutedEventArgse)
{
}
53. 打开 MainPage.xaml.cs 找到以下注释部分:
C#
private void btnUseEmailAddress_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to use saved email address page
}
54. 用以下代码替换掉注释部分:
C#
private void btnUseEmailAddress_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
new Uri("/Views/UseEmailAddressPage.xaml", UriKind.Relative));
}
55. 打开 the UseEmailAddressPage.xaml.cs.
56. 添加以下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
57. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法在应用程序墓碑化的时候输入调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of UseEmailAddressPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of UseEmailAddressPage\t ***");
base.OnNavigatedTo(e);
}
在这个页面中,我们将会选择在前面添加的其中一个联系人发送电子邮件,为了得到Email,我们将会使用EmailAddressChooserTask 类. 它启动联系人应用程序并取到一个用户选择的联系人的电子邮件. 这个 chooser 是异步的,因此你必须在启动它之前订阅 “Completed” 事件. 当选择完成返回Email地址之后我们使用EmailComposeTask 来发送电子邮件,前面我们已经完成此练习.
58. 添加下面的变量:
C#
EmailAddressChooserTask emailAddressChooserTask;
59. 在构造函数中添加以下代码:
C#
public UseEmailAddressPage()
{
InitializeComponent();
Debug.WriteLine("***\t Inconstructor of UseEmailAddressPage\t ***");
emailAddressChooserTask = new EmailAddressChooserTask();
emailAddressChooserTask.Completed += newEventHandler<EmailResult>(emailAddressChooserTask_Completed);
}
60. 使用以下的代码添加emailAddressChooserTask_Completed 事件:
C#
void emailAddressChooserTask_Completed(object sender, EmailResult e)
{
string debugMsg = string.Format(
"***\t InemailAddressChooserTask_Completed function of UseEmailAddressPage, emailaddress returned: {0}, for contact: {1}\t ***",
e.Email,e.DisplayName);
Debug.WriteLine(debugMsg);
if (e.TaskResult == TaskResult.OK)
{
EmailComposeTaskemailComposeTask = new EmailComposeTask();
emailComposeTask.Body = "Hi, will you attend the meeting tomorrow?";
emailComposeTask.To = e.Email;
emailComposeTask.Show();
}
else if (e.TaskResult == TaskResult.Cancel)
MessageBox.Show("Cannot send email without the email address","Email address not selected", MessageBoxButton.OK);
else
MessageBox.Show("Error getting email address:\n" +e.Error.Message, "Fail", MessageBoxButton.OK);
}
61. 添加 btnSendEmail_Click 事件:
C#
private void btnSendEmail_Click(object sender, RoutedEventArgse)
{
if (Microsoft.Devices.Environment.DeviceType == Microsoft.Devices.DeviceType.Device)
{
emailAddressChooserTask.Show();
}
else
{
MessageBox.Show("Thistask doesn't work properly on the Window Phone emulator.\nPlease use a realdevice!");
}
}
注意: 这段代码不会启动 EmailAddressChooserTask 如果应用程序没有运行在设备上,这是因为前面我们提到的模拟器的限制.
62. 按 F5 编译并运行应用程序.
63. 导航到 “Use Contact’s Email Address” 页面并单击 Send Email:
图 52
发送电子邮件
64. 选择联系人.
图 53
选择一个联系人
65. 如果一个联系人有多个电子邮件地址,会有额外的选择步骤,这里我们选择其中一个邮件地址.
66. 编写电子邮件(或者保持前面的文本)并单击 Send.
67. 返回到应用程序单击Back ().
68. 按 SHIFT+F5 停止调试并返回到编辑模式.
69. 在 Views 文件夹添加另外一个页面命名为ChoosePhotoPage.
注意: 为了添加一个新页面, 右键 点击Views 文件夹, 从下拉菜单中选择 Add 然后从下拉菜单中选择New Item.
70. 找到PhoneApplicationPage 元素.
71. 修改SupportedOrientations 属性的值为PortraitOrLandscape:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.ChoosePhotoPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
72. 为了简化设计过程,使用以下的代码替换整个LayoutRoot:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinitionHeight="Auto"/>
<RowDefinitionHeight="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResourceAppName}" Style="{StaticResourcePhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle"Text="Photos" Margin="9,-7,0,0"Style="{StaticResourcePhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<GridGrid.Row="0">
<Grid.RowDefinitions>
<RowDefinitionHeight="Auto" />
<RowDefinitionHeight="*" />
</Grid.RowDefinitions>
<Button x:Name="btnChoosePhoto"Content="Choose a Photo" Grid.Row="0"Click="btnChoosePhoto_Click"/>
<Image x:Name="imgChosenPhoto"Grid.Row="1" />
</Grid>
</Grid>
</Grid>
73. 打开 ChoosePhotoPage.xaml.cs.
74. 添加 button click事件到 ChoosePhotoPage.xaml.cs 类.
C#
private void btnChoosePhoto_Click(object sender, RoutedEventArgse)
{
}
75. 打开 MainPage.xaml.cs 并找到以下注释部分:
C#
private void btnChoosePhoto_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to choose photo page
}
76. 使用以下代码替换整个注释部分:
C#
private void btnChoosePhoto_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/ChoosePhotoPage.xaml", UriKind.Relative));
}
77. 打开 ChoosePhotoPage.xaml.cs.
78. 添加以下的引用声明:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
using System.Windows.Media.Imaging;
79. 重写OnNavigatedFrom 和 OnNavigatedTo 方法在墓碑化的时候输出调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of ChoosePhotoPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of ChoosePhotoPage\t ***");
base.OnNavigatedTo(e);
}
在这个页面我们将会从相册中选择一张照片.我们将会使用PhotoChooserTask 类. 它启动照片选择器在相册中选择一张照片. 这个 chooser 是异步的,因此你必须在启动它之前订阅完成事件 . 当chooser返回图片文件流时,页面将会显示这张图片.
80. 添加以下的变量:
C#
PhotoChooserTask photoChooserTask;
81. 在构造函数中添加以下代码:
C#
public ChoosePhotoPage()
{
InitializeComponent();
Debug.WriteLine("***\t Inconstructor of ChoosePhotoPage\t ***");
photoChooserTask= new PhotoChooserTask();
photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
}
82. 添加 photoChooserTask_Completed 事件来处理完成时的逻辑:
C#
void photoChooserTask_Completed(objectsender, PhotoResult e)
{
Debug.WriteLine("***\t In photoChooserTask_Completedfunction of ChoosePhotoPage\t ***");
if (e.TaskResult == TaskResult.OK)
{
BitmapImage bitmap = newBitmapImage();
bitmap.SetSource(e.ChosenPhoto);
imgChosenPhoto.Source = bitmap;
}
else if (e.TaskResult== TaskResult.Cancel)
MessageBox.Show("Nophoto was chosen - operation was cancelled", "Photo not chosen", MessageBoxButton.OK);
else
MessageBox.Show("Errorwhile choosing photo:\n" + e.Error.Message, "Fail", MessageBoxButton.OK);
}
83. 添加 btnChoosePhoto_Click 事件:
C#
private void btnChoosePhoto_Click(object sender, RoutedEventArgse)
{
photoChooserTask.Show();
}
84. 按 F5 编译运行程序.
85. 导航到 “Choose a Photo” 页然后点击 Choose a Photo:
图 54
选择照片
86. 在Image Hub中单击选取一个图片.
Figure 55
从Image Hub中选取一个图片
87. 选择的图片出现在ChoosePhotoPage.
Figure 56
Chosenphoto appears in the ChoosePhotoPage
88. 在Views文件夹填加另一个页面 TakePicturePage.
Note: 为了添加一个新页面, 右键 点击Views 文件夹, 从下拉菜单中选择 Add 然后从下拉菜单中选择New Item.
89. 定位到新创建页的PhoneApplicationPage 元素.
90. 修改SupportedOrientations 属性为 PortraitOrLandscape:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.TakePicturePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
91. 为省略篇幅直接替换下面加亮的代码到LayoutRoot 下Grid的内容:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinitionHeight="Auto"/>
<RowDefinitionHeight="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResourceAppName}" Style="{StaticResourcePhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle"Text="Pictures" Margin="9,-7,0,0"Style="{StaticResourcePhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<GridGrid.Row="0">
<Grid.RowDefinitions>
<RowDefinitionHeight="Auto" />
<RowDefinitionHeight="*" />
<RowDefinitionHeight="Auto" />
</Grid.RowDefinitions>
<Button x:Name="btnTakePicture"Content="Capture New Picture" Grid.Row="0"Click="btnTakePicture_Click"/>
<Image x:Name="imgTakenPicture"Grid.Row="1" />
<StackPanelGrid.Row="2">
<CheckBox x:Name="chkAddToImageHub"Content="Add to Image Hub" IsChecked="False"IsEnabled="False" />
<Button x:Name="btnSavePicture"Content="Save Picture" IsEnabled="False"Click="btnSavePicture_Click" />
</StackPanel>
</Grid>
</Grid>
</Grid>
92. 打开 TakePicturePage.xaml.cs.
93. 填加下面 picture button click事件处理函数到文件TakePicturePage.xaml.cs 的末尾.
(代码 – Choosers and Launchers – Ex2 任务 1 步骤 93 – picture button clicksevent handler)
C#
private void btnTakePicture_Click(object sender, RoutedEventArgse)
{
}
private void btnSavePicture_Click(objectsender, RoutedEventArgs e)
{
}
94. 打开 MainPage.xaml.cs 定位到如下注释:
C#
private void btnTakePicture_Click(object sender, RoutedEventArgse)
{
//TODO - navigate to take picture page
}
95. 用下列代码替换注释:
C#
private void btnTakePicture_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(new Uri("/Views/TakePicturePage.xaml", UriKind.Relative));
}
96. 打开文件 TakePicturePage.xaml.cs.
97. 填加下面代码:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
usingSystem.Windows.Media.Imaging;
usingSystem.IO.IsolatedStorage;
usingSystem.IO;
usingMicrosoft.Xna.Framework.Media;
98. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法,让程序在墓碑状态时记录调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of TakePicturePage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of TakePicturePage\t ***");
base.OnNavigatedTo(e);
}
在这页中,一张新的图片被拍下并且保存在电话中。拍照片用的是CameraCaptureTask类。这个类允许应用程序运行拍照程序并且用相机的摄像头拍照。这个过程是异步的,所以需要注册其完成事件。当它带着图片流返回的时候,页面会将其保存到独立存储区。
99. 填加下面的代码:
C#
CameraCaptureTask cameraCaptureTask;
100. 填加下面加亮部分的代码到方法InitializeComponent 之后:
C#
public TakePicturePage()
{
InitializeComponent();
Debug.WriteLine("***\t Inconstructor of TakePicturePage\t ***");
cameraCaptureTask= new CameraCaptureTask();
cameraCaptureTask. Completed += new EventHandler<PhotoResult>(cameraCaptureTask_Completed);
}
101. 填加 cameraCaptureTask_Completed 事件处理方法来处理完成事件:
C#
void cameraCaptureTask_Completed(objectsender, PhotoResult e)
{
Debug.WriteLine("***\t IncameraCaptureTask_Completed function of TakePicturePage\t ***");
if (e.TaskResult == TaskResult.OK)
{
BitmapImage bitmap = newBitmapImage();
bitmap.SetSource(e.ChosenPhoto);
imgTakenPicture.Source = bitmap;
chkAddToImageHub.IsEnabled = true;
btnSavePicture.IsEnabled = true;
}
else if (e.TaskResult== TaskResult.Cancel)
MessageBox.Show("Photowas not captured - operation was cancelled", "Photo not captured", MessageBoxButton.OK);
else
MessageBox.Show("Errorwhile capturing photo:\n" + e.Error.Message, "Fail", MessageBoxButton.OK);
}
102. 填加 btnTakePicture_Click 处理方法:
C#
private void btnTakePicture_Click(object sender, RoutedEventArgse)
{
cameraCaptureTask.Show();
}
注意: 记住多媒体任务在设备连接到电脑的时候是不可用的.
103. 填加下面的代码到btnSavePicture_Click 处理方法中:
C#
private void btnSavePicture_Click(object sender, RoutedEventArgse)
{
BitmapImage bitmap = (BitmapImage)imgTakenPicture.Source;
string photosStr = "Photo";
using (IsolatedStorageFilestorage = IsolatedStorageFile.GetUserStoreForApplication())
{
const string fileName= "image.jpg";
if (storage.FileExists(fileName))
{
storage.DeleteFile(fileName);
}
using (IsolatedStorageFileStreamimageFileStream = storage.CreateFile(fileName))
{
WriteableBitmap writableBitmap = new WriteableBitmap(bitmap);
writableBitmap.SaveJpeg(imageFileStream, writableBitmap.PixelWidth,writableBitmap.PixelHeight, 0, 90);
}
if (chkAddToImageHub.IsChecked.Value)
{
using (IsolatedStorageFileStreamimageFileStream = storage.OpenFile(fileName, FileMode.Open,FileAccess.Read))
{
MediaLibrary library = newMediaLibrary();
library.SavePicture(fileName, imageFileStream);
photosStr += 's';
}
}
}
MessageBox.Show(photosStr + " saved successfully", "Success", MessageBoxButton.OK);
}
注意:这段代码用的是固定的图片文件名称 – image.jpg. 建议将其存入Image Hub时给一个更合理的名称.
104. 按 F5 编译并且运行程序.
105. 导航到 “Take A Picture” 页单击 Capture New Picture:
Figure 57
初始化拍照任务
106. 在相机页中,单击:
注意: 当程序是在物理设备运行的时候,直接按设备的拍照键.
注意: TheWindows® Phone 模拟器的相机任务不会显示任何图像。模拟器的相机并没有链接到计算机的摄像头(假如有的话)。这样你看到的是屏幕中一个在屏幕边缘移动的黑色三角。
Figure 58
相机任务程序
107. 单击 Accept, 或者Retake 来拍另外一张照片.
108. 拍的图片不会显示在TakePicturePage:
图 59
图片出现在 TakePicturePage
109. 照片保存到Image Hub,选中Add to Image Hub 复选框.
110. 单击 Save Picture. 照片存储到独立存储区域并且会根据你的选择存储到Image Hub.
111. 回到应用程序,单击Back ().
112. 按 SHIFT+F5 停止调试并且回到Visual Studio.
113. 在文件夹 Views 中填加另外一个页面 UseAddressPage.
注意:填加新项,右键单击Views文件夹,选择Add,NewItem..
114. 设置 SupportedOrientations 属性为 PortraitOrLandscape:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.UseAddressPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
115. 为省略篇幅直接替换下面加亮的代码到LayoutRoot 下Grid的内容:
XAML
<!--LayoutRoot contains the root grid where allother page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application andpage title-->
<StackPanel x:Name="TitlePanel"Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Address"
Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"Grid.Row="1">
<StackPanel Orientation="Vertical"Grid.Row="0">
<TextBlock Text="Display name:"Style="{StaticResource
TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtDisplayName"IsEnabled="False"
Margin="0,0,0,10"/>
<TextBlock Text="Address:" Style="{StaticResource
TextBlockTitleLargeStyle}"/>
<TextBox x:Name="txtAddress"IsEnabled="False" Height="160" TextWrapping="Wrap"/>
<Button x:Name="btnGetAddress"Content="Get Address"
Margin="0,5" Click="btnGetAddress_Click"/>
</StackPanel>
</Grid>
</Grid>
116. 打开文件 UseAddressPage.xaml.cs.
117. 填加下面的代码到btnGetAddress_Click事件处理方法到文件UseAddressPage.xaml.cs 末尾.
C#
private void btnGetAddress_Click(objectsender, RoutedEventArgs e)
{
}
118. 打开 MainPage.xaml.cs 定位到下面注释的部分:
C#
private void btnUseAddress_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the use address page
}
119. 用下面的代码替换注释:
C#
private void btnUseAddress_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
new Uri("/Views/UseAddressPage.xaml", UriKind.Relative));
}
120. 打开 UseAddressPage.xaml.cs 文件.
121. 填加下面的代码:
C#
using Microsoft.Phone.Tasks;
using System.Diagnostics;
using System.Windows.Navigation;
122. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法,让程序在墓碑状态时记录调试信息.
C#
protected override void OnNavigatedFrom(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedFrom function of UseAddressPage\t ***");
base.OnNavigatedFrom(e);
}
protected override void OnNavigatedTo(NavigationEventArgse)
{
Debug.WriteLine("***\tIn OnNavigatedTo function of UseAddressPage\t ***");
base.OnNavigatedTo(e);
}
本页用户可能会看到选择的联系人。获取联系人的信息,页面用到了AddressChooserTask类。这个类允许用户运行联系人程序来获取用户选中的联系人信息的地址信息。由于其是异步运行的,所以需要为其注册完成事件。当其返回地址信息的时候,其内容会显示在页面中。
123. 填加下面的代码:
C#
AddressChooserTask addressChooserTask;
124. 把下面加亮的代码填入到类的构造函数中的InitializeComponent方法后面:
C#
public UseAddressPage()
{
InitializeComponent();
Debug.WriteLine("***\t Inconstructor of UseEmailAddressPage\t ***");
addressChooserTask = new AddressChooserTask();
addressChooserTask.Completed += newEventHandler<AddressResult>(addressChooserTask_Completed);
}
125. 添加 addressChooserTask_Completed 事件处理代码:
C#
void addressChooserTask_Completed(object sender, AddressResulte)
{
string debugMsg = string.Format(
"***\t In addressChooserTask_Completed function ofUseAddressPage, address returned: {0}, for contact: {1}\t ***",
e.Address,e.DisplayName);
Debug.WriteLine(debugMsg);
if (e.TaskResult == TaskResult.OK)
{
txtDisplayName.Text= e.DisplayName;
txtAddress.Text = e.Address;
}
else if (e.TaskResult== TaskResult.Cancel)
MessageBox.Show("Cannotdisplay address information.", "Addressnot selected", MessageBoxButton.OK);
else
MessageBox.Show("Errorgetting address:\n" + e.Error.Message, "Fail",MessageBoxButton.OK);
}
126. 添加下面的代码到btnGetAddress_Click 事件处理方法:
C#
private void btnGetAddress_Click(object sender, RoutedEventArgse)
{
addressChooserTask.Show();
}
127. 按 F5编译和运行程序.
128. 单击Get Address按钮打开 “Use Contact’sAddress” 页:
Figure 60
获取联系人地址
129. 选择一个联系人.
Figure 61
选择一个联系人
130. 如果一个联系人有多个地址信息,这里会再弹出一个页面让用户指定选择哪一个地址信息。
131. 选择的地址信息会出现在页面上.
132. 返回到程序,单击Back ().
133. 按 SHIFT+F5 终止调试并且返回到 Visual Studio.
任务 2 –查询联系人和约会
新版本的Windows® Phone 7.1 允许用户通过Appointments Contacts类搜索约会和联系人信息,这两个类位于Microsoft.Phone.UserData下。下面的练习会添加页面来演示这两个功能。
注意: 这部分内容用到的控件是Windows Phone Toolkit. 实验代码已经包含这些控件,但是也可以在这里获得: http://silverlight.codeplex.com/
1. 在文件夹 Views 下添加另外一个页面 SearchAppointmentsPage.
注意: 新建页面的方法,右键Views文件夹,选择Add,NewItem。.
2. 定位到新创建页面的PhoneApplicationPage元素.
3. 修改SupportedOrientations属性为 PortraitOrLandscape, 填加toolkit 命名空间以及页面的DataContext:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.SearchAppointmentsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
4. 为省略篇幅,直接添加下面加亮的代码到页面LayoutRoot的Grid下面::
XAML
<!--LayoutRootcontains the root grid where all other page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanelcontains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource AppName}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Appointments"
Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<Grid Margin="0" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox x:Name="listResults" ItemsSource="{Binding SearchResults}" VerticalAlignment="Top" Visibility="{Binding ResultsVisibility}" Margin="12,0">
<ListBox.Resources>
<conv:TimeSpanToDateTimeConverter
x:Key="TimeSpanToDateTimeConverter"/>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="12,0">
<Path Data="M15.5,159.5 L436.57007,159.5" Height="2" Stretch="Fill" Stroke="{StaticResource PhoneAccentBrush}" UseLayoutRounding="False" Margin="12,0"/>
<TextBlock Text="Start Time:"
Style="{StaticResource TextBlockTitleMediumStyle}" Margin="12,0"/>
<Grid DataContext="{Binding StartTime}" Margin="0,-10,0,-10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<toolkit:DatePicker Value="{Binding Date}" IsEnabled="False"/>
<toolkit:TimePicker Value="{Binding TimeOfDay, Converter={StaticResource TimeSpanToDateTimeConverter}}" IsEnabled="False" Grid.Column="1"/>
</Grid>
<TextBlock Text="End time:"
Style="{StaticResource TextBlockTitleMediumStyle}" Margin="12,0"/>
<Grid DataContext="{Binding EndTime}" Margin="0,-10,0,-10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<toolkit:DatePicker Value="{Binding Date}" IsEnabled="False" />
<toolkit:TimePicker Value="{Binding TimeOfDay, Converter={StaticResourceTimeSpanToDateTimeConverter}}" IsEnabled="False" Grid.Column="1"/>
</Grid>
<Path Data="M15.5,159.5L436.57007,159.5" Height="1" Stretch="Fill" Stroke="#99FFFFFF"UseLayoutRounding="False" Margin="12,0"/>
<TextBlock Text="Subject:"
Style="{StaticResource TextBlockTitleMediumStyle}" Margin="12,5,12,0"/>
<TextBlock Text="{Binding Subject}"
Style="{StaticResource TextBlockLargeStyle}" Margin="12,0,12,10"/>
<TextBlock Text="Organizer:"
Style="{StaticResource TextBlockTitleMediumStyle}"/>
<StackPanel DataContext="{Binding
Path=Organizer}" Margin="12,0,12,10">
<TextBlock Text="{Binding
Path=DisplayName}" Style="{StaticResource TextBlockLargeStyle}"/>
<TextBlock Text="{Binding
Path=EmailAddress}" Style="{StaticResource TextBlockLargeStyle}"/>
</StackPanel>
<TextBlock Text="Location:"
Style="{StaticResource TextBlockTitleMediumStyle}"/>
<TextBlock Text="{Binding Path=Location}" Margin="12,0,12,10" Style="{StaticResource TextBlockLargeStyle}"/>
<TextBlock Text="Attendees:"
Style="{StaticResource TextBlockTitleMediumStyle}"/>
<ListBox ItemsSource="{Binding
Path=Attendees}" Margin="12,0,12,10">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="6, 0, 0, 0">
<TextBlock Text="{Binding Path=DisplayName}" Style="{StaticResourceTextBlockLargeStyle}"/>
<TextBlock Text="{Binding Path=EmailAddress}" Style="{StaticResourceTextBlockLargeStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="Details:"
Style="{StaticResource TextBlockTitleMediumStyle}" Margin="12,10,12,0"/>
<TextBlock Text="{Binding Path=Details}" Style="{StaticResource TextBlockLargeStyle}" Margin="12,0,12,10"/>
<Path Data="M15.5,159.5L436.57007,159.5" Height="2" Stretch="Fill" Stroke="{StaticResourcePhoneAccentBrush}" UseLayoutRounding="False" Margin="12,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="btnNewSearch" Content="NewSearch"
Click="btnNewSearch_Click" Visibility="{Binding ResultsVisibility}" d:LayoutOverrides="Height" Grid.Row="1"/>
</Grid>
<StackPanel Orientation="Vertical" Grid.Row="0" d:IsHidden="True">
<TextBlock Text="Start time:" Visibility="{Binding SearchVisibility}" Style="{StaticResource TextBlockTitleMediumStyle}"/>
<Grid Visibility="{Binding SearchVisibility}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<toolkit:DatePicker x:Name="dateStart"/>
<toolkit:TimePicker x:Name="timeStart" Grid.Column="1"/>
</Grid>
<TextBlock Text="End time:" Visibility="{Binding SearchVisibility}" Style="{StaticResource TextBlockTitleMediumStyle}"/>
<Grid Visibility="{Binding SearchVisibility}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<toolkit:DatePicker x:Name="dateEnd" />
<toolkit:TimePicker x:Name="timeEnd" Grid.Column="1"/>
</Grid>
<Button x:Name="btnSearchAppointments"
Content="Search Appointments" Margin="0"
Click="btnSearchAppointments_Click" Visibility="{Binding SearchVisibility}"/>
</StackPanel>
</Grid>
</Grid>
5. 打开 MainPage.xaml.cs 定位到下面注释的部分:
C#
private void btnSearchAppointments_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the search appointments page
}
6. 用下面的代码替换注释:
C#
private void btnSearchAppointments_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
new Uri("/Views/SearchAppointmentsPage.xaml",UriKind.Relative));
}
7. 打开文件 SearchAppointmentsPage.xaml.cs.
8. 添加下面的代码:
C#
usingMicrosoft.Phone.UserData;
usingSystem.Collections.ObjectModel;
usingSystem.Windows.Navigation;
using System.Diagnostics;
9. 在类中添加下面的字段和属性:
C#
public ObservableCollection<Appointment>SearchResults { get;
private set; }
Appointments appointments;
public Visibility SearchVisibility
{
get { return (Visibility)GetValue(SearchVisibilityProperty);}
set {SetValue(SearchVisibilityProperty, value); }
}
public static readonly DependencyProperty SearchVisibilityProperty =
DependencyProperty.Register("SearchVisibility", typeof(Visibility),typeof(SearchAppointmentsPage),null);
public Visibility ResultsVisibility
{
get { return (Visibility)GetValue(ResultsVisibilityProperty);}
set {SetValue(ResultsVisibilityProperty, value); }
}
public static readonly DependencyProperty ResultsVisibilityProperty =
DependencyProperty.Register("ResultsVisibility", typeof(Visibility),typeof(SearchAppointmentsPage),null);
10. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法,让程序在墓碑状态时记录调试信息.
C#
protected override voidOnNavigatedFrom(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedFrom function ofSearchAppointmentsPage\t ***");
if(e.NavigationMode == NavigationMode.Back)
{
if(State.ContainsKey("StartTime"))
{
State.Remove("StartTime");
}
if(State.ContainsKey("EndTime"))
{
State.Remove("EndTime");
}
if(State.ContainsKey("ResultsVisible"))
{
State.Remove("ResultsVisible");
}
}
else
{
State["StartTime"]=
dateStart.Value.Value.Add(timeStart.Value.Value.TimeOfDay);
State["EndTime"]=
dateEnd.Value.Value.Add(timeEnd.Value.Value.TimeOfDay);
State["ResultsVisible"]= ResultsVisibility;
}
base.OnNavigatedFrom(e);
}
protected override voidOnNavigatedTo(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedTo function ofSearchAppointmentsPage\t ***");
if(State.Count > 0)
{
if(e.Uri.OriginalString.EndsWith("DatePickerPage.xaml"))
{
timeStart.Value =
new DateTime().Add(
((DateTime)State["StartTime"]).TimeOfDay);
timeEnd.Value =
newDateTime().Add(
((DateTime)State["EndTime"]).TimeOfDay);
}
if(e.Uri.OriginalString.EndsWith("TimePickerPage.xaml"))
{
dateStart.Value =
((DateTime)State["StartTime"]).Date;
dateEnd.Value =
((DateTime)State["EndTime"]).Date;
}
ResultsVisibility = (Visibility)State["ResultsVisible"];
SearchVisibility = ResultsVisibility ==Visibility.Visible ?
Visibility.Collapsed: Visibility.Visible;
// Refreshthe search
if(ResultsVisibility == Visibility.Visible)
{
btnSearchAppointments_Click(this, null);
}
}
base.OnNavigatedTo(e);
}
在本页中用户利用Appointments chooser通过两个时间点来查找约会。由于其是异步执行的所以需要为其注册完成事件。当它返回相应的约会信息时,会显示在页面上。
11. 把下面加亮的代码填入到类的构造函数中的InitializeComponent方法后面:
C#
public UseAddressPage()
{
InitializeComponent();
Debug.WriteLine("***\tIn constructor of SearchAppointments\t ***");
SearchResults = new ObservableCollection<Appointment>();
ResultsVisibility= Visibility.Collapsed;
SearchVisibility= Visibility.Visible;
appointments = new Appointments();
appointments.SearchCompleted+= new
EventHandler<AppointmentsSearchEventArgs>(appointments_SearchCompleted);
}
12. 添加 appointments_SearchCompleted 事件处理代码,以及一个方法来处理完成事件:
C#
voidappointments_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
{
Dispatcher.BeginInvoke(() =>UpdateResults(e.Results));
}
private void UpdateResults(IEnumerable<Appointment> result)
{
SearchResults.Clear();
foreach (Appointment appointment inresult)
{
SearchResults.Add(appointment);
}
ResultsVisibility = Visibility.Visible;
SearchVisibility = Visibility.Collapsed;
}
13. 添加下面的代码响应界面上按钮的单击事件:
C#
private void btnSearchAppointments_Click(object sender, RoutedEventArgse)
{
if(!dateStart.Value.HasValue || !timeStart.Value.HasValue)
{
MessageBox.Show("Please supply a start time.");
return;
}
if(!dateEnd.Value.HasValue || !timeEnd.Value.HasValue)
{
MessageBox.Show("Please supply an end time.");
return;
}
appointments.SearchAsync(dateStart.Value.Value.Add(timeStart.Value.Value.TimeOfDay),
dateEnd.Value.Value.Add(timeEnd.Value.Value.TimeOfDay), null);
}
private void btnNewSearch_Click(objectsender, RoutedEventArgs e)
{
SearchVisibility = Visibility.Visible;
ResultsVisibility = Visibility.Collapsed;
}
14. 按 F5 编译并运行程序.
15. 导航到 “Search Appointments”页面填写起始事件和结束事件,然后按 “SearchAppointments” 按钮:
Figure 62
查找约会信息
Figure 63
查找到的约会信息
16. 相关的联系人信息显示在了页面上.
17. 返回程序,按Back ().
18. 按 SHIFT+F5终止调试并且返回到 the Visual Studio.
19. 在文件夹 Views 下创建新页面 FindNextAppointmentPage.
注意: 新建页面的方法,右键Views文件夹,选择Add,NewItem。
20. 定位到新创建页面的PhoneApplicationPage元素.
21. 修改SupportedOrientations属性为 PortraitOrLandscape, 填加toolkit 命名空间以及页面的DataContext:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.FindNextAppointmentPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
22. 为省略篇幅,直接添加下面加亮的代码到页面LayoutRoot的Grid下面:
XAML
<!--LayoutRootcontains the root grid where all other page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanelcontains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Appointments"
Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<ScrollViewer>
<StackPanel Orientation="Vertical" Grid.Row="0"
DataContext="{Binding Path=FirstAppointment}">
<StackPanel.Resources>
<conv:TimeSpanToDateTimeConverter
x:Key="TimeSpanToDateTimeConverter"/>
</StackPanel.Resources>
<Button x:Name="btnFindNext"
Content="Find Next Appointment" Margin="0,5" Click="btnFindNext_Click"/>
<TextBlock Text="Start Time:"
Style="{StaticResource TextBlockTitleMediumStyle}" Margin="12,0"/>
<Grid DataContext="{Binding StartTime}"
Margin="0,-10,0,-10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<toolkit:DatePicker Value="{Binding Date}"
IsEnabled="False" />
<toolkit:TimePicker Value="{Binding TimeOfDay,
Converter={StaticResource TimeSpanToDateTimeConverter}}"
IsEnabled="False" Grid.Column="1"/>
</Grid>
<TextBlock Text="End time:" Style="{StaticResource
TextBlockTitleMediumStyle}" Margin="12,0"/>
<Grid DataContext="{Binding EndTime}"
Margin="0,-10,0,-10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<toolkit:DatePicker Value="{Binding Date}"
IsEnabled="False"/>
<toolkit:TimePicker Value="{Binding TimeOfDay,
Converter={StaticResource TimeSpanToDateTimeConverter}}"
IsEnabled="False" Grid.Column="1"/>
</Grid>
<Path Data="M15.5,159.5L436.57007,159.5" Height="1"
Stretch="Fill" Stroke="#99FFFFFF" UseLayoutRounding="False"
Margin="12,0"/>
<TextBlock Text="Subject:" Style="{StaticResource
TextBlockTitleMediumStyle}" Margin="12,5,12,0"/>
<TextBlock Text="{Binding Path=Subject}"
Style="{StaticResource TextBlockLargeStyle}" Margin="12,0,12,10"/>
<TextBlock Text="Organizer:" Style="{StaticResource
TextBlockTitleMediumStyle}"/>
<StackPanel DataContext="{Binding Path=Organizer}"
Margin="12,0,12,10">
<TextBlock Text="{Binding Path=DisplayName}"
Style="{StaticResource TextBlockLargeStyle}"/>
<TextBlock Text="{Binding Path=EmailAddress}"
Style="{StaticResource TextBlockLargeStyle}"/>
</StackPanel>
<TextBlock Text="Location:" Style="{StaticResource
TextBlockTitleMediumStyle}"/>
<TextBlock Text="{Binding Path=Location}"
Margin="12,0,12,10" Style="{StaticResource TextBlockLargeStyle}"/>
<TextBlock Text="Attendees:" Style="{StaticResource
TextBlockTitleMediumStyle}"/>
<ListBox ItemsSource="{Binding Path=Attendees}"
Margin="12,0,12,10">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="6, 0, 0, 0">
<TextBlock Text="{Binding
Path=DisplayName}" Style="{StaticResource TextBlockLargeStyle}"/>
<TextBlock Text="{Binding
Path=EmailAddress}" Style="{StaticResource TextBlockLargeStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="Details:" Style="{StaticResource
TextBlockTitleMediumStyle}" Margin="12,10,12,0"/>
<TextBlock Text="{Binding Path=Details}"
Style="{StaticResource TextBlockLargeStyle}" Margin="12,0,12,10"/>
</StackPanel>
</ScrollViewer>
</Grid>
</Grid>
23. 打开文件 MainPage.xaml.cs 并且定位到注释部分:
C#
private void btnFindNextMeeting_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the search appointments page
}
24. 用下面的代码替换注释代码:
C#
private void btnFindNextMeeting_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
new Uri("/Views/FindNextAppointmentPage.xaml",UriKind.Relative));
}
25. 打开文件 FindNextAppointmentPage.xaml.cs.
26. 添加下面的代码:
C#
usingMicrosoft.Phone.UserData;
usingSystem.Windows.Navigation;
using System.Diagnostics;
27. 在类里添加下面的字段和属性:
C#
Appointments appointments;
public Appointment FirstAppointment
{
get { return (Appointment)GetValue(FirstAppointmentProperty);}
set {SetValue(FirstAppointmentProperty, value); }
}
public static readonly DependencyProperty FirstAppointmentProperty =
DependencyProperty.Register("FirstAppointment", typeof(Appointment),typeof(FindNextAppointmentPage),null);
28. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法,让程序在墓碑状态时记录调试信息.
C#
protected override voidOnNavigatedFrom(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedFrom function ofFindFirstAppointmentPage\t ***");
base.OnNavigatedFrom(e);
}
protected override voidOnNavigatedTo(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedTo function ofFindFirstAppointmentPage\t ***");
base.OnNavigatedFrom(e);
if(!e.IsNavigationInitiator)
{
btnFindNext_Click(this, null);
}
}
本页中通过Appointments Chooser查找到最近的约会信息。由于其是异步执行的所以需要为其注册完成事件。当它返回相应的约会信息时,会显示在页面上。
29. 把下面加亮的代码填入到类的构造函数中的InitializeComponent方法后面:
C#
public UseAddressPage()
{
InitializeComponent();
Debug.WriteLine("***\tIn constructor of FindNextAppointmentPage\t ***");
appointments = new Appointments();
appointments.SearchCompleted += new
EventHandler<AppointmentsSearchEventArgs>(appointments_SearchCompleted);
}
30. 添加appointments_SearchCompleted 事件处理代码,以及另外一个方法来处理完成事件:
C#
private void appointments_SearchCompleted(object sender,
AppointmentsSearchEventArgs e)
{
Dispatcher.BeginInvoke(() =>
UpdateResults(e.Results.FirstOrDefault()));
}
private void UpdateResults(Appointmentresult)
{
if (result== null)
{
MessageBox.Show("There are no appointments.");
return;
}
FirstAppointment = result;
}
31. 添加下面的代码响应页面上的按钮事件:
C#
private void btnFindNext_Click(objectsender, RoutedEventArgs e)
{
appointments.SearchAsync(DateTime.Now, DateTime.MaxValue,1, null);
}
32. 按 F5 编译和运行程序.
33. 导航到 “Find Next Appointments” 页,按下 “Find Next Appointment” 按钮:
Figure 64
显示下一条约会信息
34. 相关的约会信息显示在了页面上.
35. 返回程序,按Back ().
36. 按 SHIFT+F5终止调试并且返回到 Visual Studio.
37. 在文件夹 Views下填加子文件夹Resources.
注意: 新建文件夹的方法,右键Views文件夹,选择Add,NewFolder。.
38. 添加文件 ContactListDictionary.xaml, 可以在 Source\Assets 文件夹下找到上节创建的文件夹,文件定义了用户接口模版,这个是用来接下来我们用于显示存储在设备上的联系人信息的。
39. 在文件夹 Views下新建一个页面ShowContactsPage.
注意:新建页面的方法,右键Views文件夹,选择Add,NewItem。定位到新创建页面的 the PhoneApplicationPage元素.
40. 修改SupportedOrientations 属性为 PortraitOrLandscape, 添加toolkit 命名空间以及页面的DataContext。:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.ShowContactsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
41. 立即在PhoneApplicationPage元素后面,添加下面这段在第38步使用到的Xaml资源片段:
XAML
<phone:PhoneApplicationPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Resources/ContactListDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</phone:PhoneApplicationPage.Resources>
42. 为省略篇幅,直接添加下面加亮的代码到页面LayoutRoot的Grid下面:
XAML
<!--LayoutRootcontains the root grid where all other page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanelcontains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="{StaticResource
AppName}"Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Contacts"
Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<conv:VisibilityInvertConvertor
x:Key="VisibilityInvertConvertor"/>
</Grid.Resources>
<StackPanel VerticalAlignment="Center" Visibility="{Binding
Path=ContactsListVisibility, Converter={StaticResource
VisibilityInvertConvertor}}">
<TextBlock Text="Loading Contacts..."
HorizontalAlignment="Center" Style="{StaticResource
TextBlockMediumStyle}"/>
<ProgressBar IsIndeterminate="True"/>
</StackPanel>
<toolkit:LongListSelector ItemsSource="{Binding
Path=ContactsCollection}" ItemTemplate="{StaticResource
ContactItemTemplate}" Visibility="{Binding Path=ContactsListVisibility}" GroupHeaderTemplate="{StaticResource ContactsGroupHeaderTemplate}"
GroupItemTemplate="{StaticResource ContactsGroupItemTemplate}"
GroupItemsPanel="{StaticResource ContactGroupViewTemplate}"/>
</Grid>
</Grid>
43. 在 PhoneApplicationPage元素结尾之前,你应该会看到两段注释,其中第一段以“Sample code showing usage of ApplicationBar”开头. 用下面的代码替换掉Xaml注释:
XAML
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True"IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="Images/Search.png"
Text="Search" Click="ApplicationBarSearchButton_Click"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
44. 打开 MainPage.xaml.cs 定位到下面注释的部分:
C#
private void btnSearchContacts_Click(object sender, RoutedEventArgse)
{
//TODO - navigateto the search contacts page
}
45. 用下面的代码替换注释:
C#
private void btnSearchContacts_Click(object sender, RoutedEventArgse)
{
NavigationService.Navigate(
new Uri("/Views/ShowContactsPage.xaml",UriKind.Relative));
}
46. 打开文件 ShowContactsPage.xaml.cs.
47. 添加下面的代码:
C#
usingSystem.Collections.ObjectModel;
usingSystem.Windows.Navigation;
usingMicrosoft.Phone.UserData;
using System.Collections;
using System.Diagnostics;
48. 为类添加下面的字段和属性:
C#
private Contacts contacts;
public ObservableCollection<ContactsGroup>ContactsCollection
{
get { return (ObservableCollection<ContactsGroup>)GetValue(
ContactsCollectionProperty); }
set {SetValue(ContactsCollectionProperty, value); }
}
public static readonly DependencyProperty ContactsCollectionProperty =
DependencyProperty.Register("ContactsCollection", typeof(ObservableCollection<ContactsGroup>), typeof(ShowContactsPage), null);
public Visibility ContactsListVisibility
{
get { return (Visibility)GetValue(ContactsListVisibilityProperty);}
set {SetValue(ContactsListVisibilityProperty, value);}
}
public static readonly DependencyProperty ContactsListVisibilityProperty= DependencyProperty.Register("ShowContactsList", typeof(Visibility),typeof(ShowContactsPage),null);
49. 重写 OnNavigatedFrom 和 OnNavigatedTo 方法,让程序在墓碑状态时记录调试信息.
C#
protected override voidOnNavigatedFrom(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedFrom function ofShowContactsPage\t ***");
base.OnNavigatedFrom(e);
// Hide thecontacts list if we go back to the main page
if(e.IsNavigationInitiator && e.NavigationMode ==
NavigationMode.Back)
{
ContactsListVisibility = Visibility.Collapsed;
((App)App.Current).ShowContactsPage = null;
}
}
protected override voidOnNavigatedTo(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedTo function ofShowContactsPage\t ***");
base.OnNavigatedTo(e);
((App)App.Current).ShowContactsPage = this;
// Refresh thecontact list unless it is already visible (we make
// sure it is not visible if it needs a
// refresh)
if(ContactsListVisibility == Visibility.Collapsed)
{
contacts.SearchAsync(String.Empty, FilterKind.None,null);
}
}
在本页中会显示用户在联系人界面中选取的联系人信息。由于其是异步的所以需要为其注册完成事件。当它返回联系人信息的时候,会显示在程序的页面上。
50. 把下面加亮的代码填入到类的构造函数中的InitializeComponent方法后面:
C#
public ShowContactsPage()
{
InitializeComponent();
Debug.WriteLine("***\tIn constructor of ShowContactsPage\t ***");
ContactsListVisibility = Visibility.Collapsed;
ContactsCollection = new ObservableCollection<ContactsGroup>();
contacts = new Contacts();
contacts.SearchCompleted +=contacts_SearchCompleted;
}
类 ContactsGroup 用来在联系人显示之前对其进行分组,我们将会在后面创建它。
51. 用下面的代码添加contacts_SearchCompleted事件处理方法:
C#
voidcontacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
// Group allcontacts according to the first letter in their display
// name
varitemsSource = e.Results.GroupBy(c => c.DisplayName.First()).
OrderBy(group =>group.Key).Select(group => new ContactsGroup(
group));
Dispatcher.BeginInvoke(() =>
{
ContactsListVisibility = Visibility.Visible;
ContactsCollection =
newObservableCollection<ContactsGroup>(itemsSource);
});
}
52. 添加下面的代码来处理应用程序栏按钮按下的事件,它会将我们引导到另外一个搜索页面:
C#
private void ApplicationBarSearchButton_Click(object sender,
EventArgs e)
{
NavigationService.Navigate(new Uri("/Views/SearchContactsPage.xaml",
UriKind.Relative));
}
53. 在文件里添加另外一个类. 这个类就是我们前面提到过的 ContactsGroup:
C#
public class ContactsGroup : IEnumerable<Contact>
{
private IEnumerable<Contact> items;
public string Title { get; set; }
/// <summary>
/// Creates a new groupof contracts. The group's title will be the
/// first letter in thefirst contact's display name.
/// </summary>
/// <paramname="items">The contacts to include in the group.
/// </param>
public ContactsGroup(IEnumerable<Contact> items)
{
this.items= items;
Title = char.ToLower(items.First().DisplayName.First()).
ToString();
}
#regionIEnumerable<Contact> Members
public IEnumerator<Contact>GetEnumerator()
{
returnitems.GetEnumerator();
}
#endregion
#regionIEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
returnitems.GetEnumerator();
}
#endregion
}
54. 按 F5编译运行程序.
55. 导航到“Search Contacts” 页,可以看到设备的联系人信息:
Figure 65
显示设备的联系人信息
按应用程序栏的按钮会导致程序崩溃,因为转向的页面我们还没有完成,我们会在下面完成相关的页面。
56. 返回到程序,单击Back ().
57. 按 SHIFT+F5 终止调试并且返回到Visual Studio.
58. 在文件夹 Views 下添加另外一个页面 SearchContactsPage.
注意: 为了添加一个新页面, 右键 点击Views 文件夹, 从下拉菜单中选择 Add 然后从下拉菜单中选择New Item.
59. 在新创建页中定位到 PhoneApplicationPage 元素.
60. 设置 SupportedOrientations 属性为 PortraitOrLandscape, 填加 toolkit 命名控件并且添加页面的data context,如下所示:
XAML
<phone:PhoneApplicationPage
x:Class="LaunchersAndChoosers.Views.ShowContactsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
61. 在PhoneApplicationPag元素之后, 添加下面这段在38中使用到的Xaml资源片段:
XAML
<phone:PhoneApplicationPage.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="Resources/ContactListDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</phone:PhoneApplicationPage.Resources>
62. 便于精简,使用下面加亮的代码完全替换LayoutRoot主Grid里的内容:
XAML
<!--LayoutRootcontains the root grid where all other page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanelcontains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle" Margin="-3,-8,0,0" Text="CONTACTS" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Search" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel- place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Vertical" Grid.Row="0"
Margin="0,2,0,-2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Search by:" Grid.Column="0"
Style="{StaticResource TextBlockTitleMediumStyle}"/>
<toolkit:ListPicker x:Name="listFilterType"
Grid.Column="1">
<toolkit:ListPickerItem>DisplayName
</toolkit:ListPickerItem>
<toolkit:ListPickerItem>Email
</toolkit:ListPickerItem>
<toolkit:ListPickerItem>PhoneNumber
</toolkit:ListPickerItem>
</toolkit:ListPicker>
</Grid>
<TextBox x:Name="txtSearchTerm"/>
</StackPanel>
<toolkit:LongListSelector x:Name="listSearchResults" ItemsSource="{Binding SearchResults}" Grid.Row="1" IsFlatList="True" ItemTemplate="{StaticResource ContactItemTemplate}"/>
</Grid>
</Grid>
</Grid>
63. 打开ShowContactsPage.xaml.c文件.
64. 添加下面的代码:
C#
usingMicrosoft.Phone.UserData;
usingSystem.Collections.ObjectModel;
usingSystem.Windows.Navigation;
using System.Diagnostics;
65. 添加下面的字段和属性:
C#
private object syncObject = new object();
private bool searchInProgress = false;
private bool searchQueued = false;
Dictionary<string, FilterKind> filterDictionary;
private Contacts contacts;
public ObservableCollection<Contact> SearchResults
{
get { return (ObservableCollection<Contact>)GetValue(
SearchResultsProperty); }
set {SetValue(SearchResultsProperty, value); }
}
public static readonly DependencyProperty SearchResultsProperty =
DependencyProperty.Register("SearchResults", typeof(ObservableCollection<Contact>), typeof(SearchContactsPage), null);
66. 重写OnNavigatedFrom和OnNavigatedTo 方法以当程序处于墓碑状态填加调试信息并且在退回到这个界面的时候刷新查询结果信息.
C#
protected override voidOnNavigatedFrom(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedFrom function ofSearchContactsPage\t ***");
if(e.NavigationMode == NavigationMode.Back)
{
if (State.ContainsKey("SearchTerm"))
{
State.Remove("SearchTerm");
}
if(State.ContainsKey("FilterIndex"))
{
State.Remove("FilterIndex");
}
}
else
{
State["SearchTerm"]= txtSearchTerm.Text;
State["FilterIndex"]= listFilterType.SelectedIndex;
}
base.OnNavigatedFrom(e);
}
protected override voidOnNavigatedTo(NavigationEventArgs e)
{
Debug.WriteLine("***\t In OnNavigatedTo function ofSearchContactsPage\t ***");
base.OnNavigatedTo(e);
if(State.ContainsKey("SearchTerm"))
{
txtSearchTerm.Text = State["SearchTerm"].ToString();
}
if(State.ContainsKey("FilterIndex"))
{
listFilterType.SelectedIndex = (int)State["FilterIndex"];
}
}
在这页里用户可以根据显示名称,电子邮件或者电话号码来搜索联系人。这就是靠Contacts Chooser实现的。下面加入一个方法来初始化用户在查询条件框里的输入。
67. 把下面加亮的代码填入到类的构造函数中的InitializeComponent方法后面:
C#
public ShowContactsPage()
{
InitializeComponent();
Debug.WriteLine("***\t In constructor of SearchContactsPage\t***");
SearchResults = newObservableCollection<Contact>();
InitializeFilterDictionary();
contacts = newContacts();
contacts.SearchCompleted +=contacts_SearchCompleted;
listFilterType.SelectionChanged +=listFilterType_SelectionChanged;
txtSearchTerm.KeyUp += txtSearchTerm_KeyUp;
}
68. 添加InitializeFilterDictionary 方法, that will link the entries available to the user through the UI toactual contacts search types:
C#
private void InitializeFilterDictionary()
{
filterDictionary = newDictionary<string,FilterKind>();
filterDictionary["DisplayName"] = FilterKind.DisplayName;
filterDictionary["Email"]= FilterKind.EmailAddress;
filterDictionary["PhoneNumber"] = FilterKind.PhoneNumber;
}
69. 添加 listFilterType_SelectionChanged 事件处理方法来处理用户选择不同的查询方法:
C#
voidlistFilterType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
InputScopescope = new InputScope();
InputScopeNamename = new InputScopeName();
switch(filterDictionary[(listFilterType.SelectedItem asListPickerItem).Content.ToString()])
{
case FilterKind.DisplayName:
name.NameValue = InputScopeNameValue.Default;
scope.Names.Add(name);
txtSearchTerm.InputScope = scope;
break;
case FilterKind.EmailAddress:
name.NameValue = InputScopeNameValue.EmailNameOrAddress;
scope.Names.Add(name);
txtSearchTerm.InputScope = scope;
break;
case FilterKind.PhoneNumber:
name.NameValue = InputScopeNameValue.Number;
scope.Names.Add(name);
txtSearchTerm.InputScope = scope;
break;
default:
break;
}
QueueSearch();
}
注意上面的方法在输入搜索关键字的时候会根据搜索方式更改键盘上显示的内容。
70. 添加 QueueSearch 方法. 这个方法执行一个不在进行中的查询:
C#
private void QueueSearch()
{
lock(syncObject)
{
if(searchInProgress)
{
searchQueued = true;
return;
}
searchInProgress = true;
PerformSearch();
}
}
71. 添加 PerformSearch 方法来执行查询:
C#
private void PerformSearch()
{
if (String.IsNullOrEmpty(txtSearchTerm.Text))
{
// There isnothing to look for
SearchResults.Clear();
searchInProgress = false;
return;
}
contacts.SearchAsync(txtSearchTerm.Text, filterDictionary[(listFilterType.SelectedItemas ListPickerItem).Content.ToString()],null);
}
72. 添加 txtSearchTerm_KeyUp 事件处理方法来初始化用户的输入。:
C#
void txtSearchTerm_KeyUp(object sender, KeyEventArgse)
{
QueueSearch();
}
73. 添加 contacts_SearchCompleted 事件处理方法, 实现的方法为当查询完成的时候对UI进行更新:
C#
private void contacts_SearchCompleted(object sender, ContactsSearchEventArgse)
{
Dispatcher.BeginInvoke(() =>
{
try
{
SearchResults =
newObservableCollection<Contact>(e.Results);
}
catch
{
// Ignoreexceptions, which are caused by searching for a
// phonenumber with a string that does not contains digits // alone
}
finally
{
lock(syncObject)
{
searchInProgress = false;
if(searchQueued == true)
{
//A search was queued while already searching.
//Try performing it again.
searchQueued = false;
QueueSearch();
}
}
}
});
}
74. 按F5 编译运行程序.
75. 导航到前面创建的 “Search Contacts” 页面,点击application bar的Search按钮:
图 66
查找联系人。
选择搜索模式然后输入检索条件。
76. 回到应用程序,单击Back ().
77. 按 SHIFT+F5 停止调试并且返回到 Visual Studio.
此部分有相关实验代码.
注意:示例代码的位置:Source\Ex2-Choosers\End.
本节实验演示了Windows Phone7中的Launchers和Chooser的使用。每个程序中的页面中都用到了相应的Launcher和Chooser。参考这些示例你可以在你以后的程序中很容易的使用Launcher和Choosers.