原文 Windows Phone 8初学者开发—第21部分:永久保存Wav音频文件
系列地址:http://channel9.msdn.com/Series/Windows-Phone-8-Development-for-Absolute-Beginners
源代码: http://aka.ms/absbeginnerdevwp8
PDF版本: http://aka.ms/absbeginnerdevwp8pdf
现在我们可以录制声音并将它保存到应用程序独立存储的临时文件中。接下来我们需要提示用户输入新的自定义声音的显示名称来允许用户永久保存声音。
本课的计划:
前面我们通过启用BuildLocalizedApplicationBar()为RecordAudio.xaml页面创建了应用栏。所以我们需要做的就是激活它:
接着,我们将在用户停止录制后启用应用栏。在RecordAudioUnchecked()方法中,我们将IsVisible属性设置为true(见以下67行):
在上面的步骤中我们为SaveRecordingClick()方法添加了一个方法存根
我将替换抛出异常作为提醒的那行代码并编写以下代码(见51行):
因为InputPrompt(输入提示)来自与我们目前使用的其它类不同的命名空间,我们需要添加一个using语句(使用悬停于蓝色虚线的方法以显示一个上下文菜单)。
接着我们将配置并显示InputPrompt:
当用户为新的自定义声音输入名称并单击勾选按钮时,FileNameCompleted()事件处理程序将被触发。
我们将通过检查结果确保用户正确退出InputPrompt。我们将检查作为输入参数发送给事件处理程序方法的 PopUpResult。如果结果是"OK",则我们就可以执行必要的逻辑来将临时文件保存为新的"永久的"声音。请查看我添加的代码以及代码的注释,这 些注释提供了一个我希望执行的"后续步骤"的一个大纲:
在注释1和2之间是一个需要做些什么以便正常工作的概述。在我们尝试实施这些想法前,让我们通过运行应用程序来确保到目前为止流程的运作与我们的期望相一致。
我使用切换按钮录制自定义声音。当我停止录制时,我将会看到应用栏的出现:
当我单击磁盘图标保存自定义声音时,将显示输入对话框:
并且当我输入声音名称并单击勾选图标时,对话框将消失并把我带回MainPage.xaml。很好!
现在让我们处理困难的部分,执行代码注释中列出的任务。
至此我们录制了自定义声音并将它作为临时文件存储,并且我们刚刚为声音收集了一个友好的显示名称。我们需要完成两项基本的任务:
所以我向FileNameCompleted()方法添加了以下代码:
然而,当我们关闭应用程序并且它被完全从手机内存中删除,将会发生什么?届时CustomSounds.Items集合 将从内存中删除,并且下一次应用程序运行时,应用程序将无法获得我们的自定义声音。我们需要一种方法存储自定义的声音数据,这样我们就可以在下次用户运行 应用程序时将其加载到我们的数据模型中。
为此我们需要将CustomSounds.Items集合序列化到一种数据格式。有许多数据格式可供选择,但是我们将选 择一种非常流行,轻量级并易于使用的格式——JSON。它是JavaScript Object Notion(JavaScript对象表示法)的缩写。它使我们方便地用JavaScript对象表示集合。如果我们利用名为Json.NET的第三方 开源库,我们甚至不用考虑数据的格式,大部分复杂性将被简单的方法调用隐藏。
首先,我们将打开NuGet程序包管理器(使用我在前面演示过的技术,右键单击引用文件夹并选择管理NuGet程序包选项)。
为验证Json.NET是否安装成功,打开SoundBoard项目的引用文件夹并验证Newtonsoft.Json将出现在那里:
回到FileNameCompleted()方法,下一步是将CustomSounds.Items转换为Json,让后将它存储到磁盘。
我们将使用Newtonsoft.Json.JsonConvert类执行转换。您需要添加适当的using语句以使用JsonConvert类:
现在我们准备实现CustomSounds Json文件到磁盘的存储。
在忘记之前,让我们在SoundModel.cs文件中定义CustomSoundKey,我将添加以下代码行(见19行):
如您所见,这是一个常量字符串值。我们希望它是常数,因为它不会改变。它只是在独立存储中找回正确的应用设置(ApplicationSetting)的一个唯一的字符串。
接着,我们将在实例化所有其它SoundGroup对象的同时加载自定义声音到内存中,在SoundModel.cs文件的LoadData()方法中:
在上述28行,我们将调用一个辅助方法LoadCustomSounds()以填充SoundModel类的CustomSounds属性。使用我在之前演示过的技术为新的方法生成一个存根。
在LoadCustomSounds()方法中,我们将尝试从IsolatedStorageSettings中检索包含序列化自定义声音的Json:
现在让我们动手测试应用程序。我将录制一个声音并尝试用名称"another test"保存该声音。
一切看起来都很好,但是当我保存新的自定义声音后返回MainPage.xaml并尝试播放它时会发现,它无法播放!这是因为我们需要修改MainPage.xaml上的播放代码以从新的文件夹加载自定义声音。目前它仅从/Assets文件夹加载。
我们的目标是将MediaElement的Source属性设置为正确的声音文件的位置,这些声音文件与用户点击的磁贴相关。我们将在两个位置查找,或者是/Assets文件夹,或者是独立存储区域。
在MainPage.xaml.cs文件的LongListSelector事件处理程序方法中,我将添加以下内容:
这里我尝试查看用户选择的磁贴是否是自定义声音。如果我们不能在Assets\文件夹定位与磁贴相关的文件,那么将在应用程序独立存储区域中的/customSounds/子文件夹中查找。
对于上述检查,我们需要访问手机的文件系统,所以我们将使用System.IO.File对象。以上截图显示了如何在代码文件顶部添加合适的using语句以包含System.IO。
此外,我们希望包含System.IO.IsolatedStorage引用,因为接下来我们将使用该命名空间中的类。
回到LongListSelector的SelectionChanged()事件处理程序方法,如果 SoundData对象的FilePath所指的文件不能在缺省位置被找到,则File.Exists()将返回false。否则,它将位于 /Assets文件夹。所以基于以上分析我编写了以下代码:
这次我们运行应用程序,录制并保存声音,然后返回“我的”自定义声音类别,每一个保存的声音应该都可以正确播放了!
综上所述,本课的重点是使用Newtonsoft Json序列化和反序列化对象到JSON,它是一个提升手机开发的非常有价值的技能。我们还学习了如何处理IsolatedStorage,特别是用 IsolatedStorageSettings来存储名称/值对。我们使用System.IO.File类来检查文件系统,并学习了如何处理流。我们还 使用了Coding4Fun工具包中的InputPrompt等内容。我们已经基本完成了应用程序,我们将进行最后的加工以使它更有趣。