《101 Windows Phone 7 Apps》读书笔记-Subservient Cat

简介:

课程内容

Ø Playing Video

Ø MediaElement

 

    Subservient Cat是一个“虚拟宠物”的应用程序。与大多数猫不一样,Subservient Cat非常听从主人的指令!但是,用户需要知道哪些命令它是能够回应的。它又带点游戏的成分,因为用户必须通过自己的摸索来发现这些命令。

该应用程序使用一段黑色猫咪(名字为Boo)的视频剪辑作为主界面。因此,对于学习怎样通过MediaElement控件在应用程序中播放视频来说,这是一个很好的例子。

 

Playing Video with MediaElement

    如果我们想要用户可以对视频进行播放、暂停和其他的控制操作,最好的选择就是使用Media Player 启动器。但是,如果我们想要在应用程序的页面中播放视频内容,就可以选择使用MediaElement。MediaElement是一个UI控件,它可以通过自身的Source属性来播放视频文件。例如:

<MediaElement Source=”cat.wmv”/>

    视频源文件的路径可以指向工程中包含的文件,或者是一个在线的网络视频。默认情况下,MediaElement在加载时自动播放视频(对于网络视频来说,只要缓冲了足够的视频流,它就开始播放),但是,我们可以将AutoPlay属性设置为false,来更改这种设置。在背后代码中,我们可以使用MediaElement的Play、Pause 和 Stop方法。它还具有Position属性,用于指示当前的播放位置(用一个时间段的值来标识)。另外,如果视频支持查找的话,我们可以设置Position为一个播放的时间点。就和其他的Silverlight 元素一样,MediaElement支持转变和剪切操作,并且它还可以与其他元素混合。从界面上来看,使用MediaElement元素很直接。但是,也有很多需要说明的地方。下面例举了5个需要注意的点:

1. 一个应用程序的frame只能包含一个MediaElement!

    在一个frame中使用多个MediaElement的做法是不被支持的,而且程序会返回失败。注意,这种限制比一个页面使用一个MediaElement还要严格;任何时候,只能有一个MediaElement加载到frame上(无论MediaElement是处于停止、暂停或者是播放状态)。因此,多个页面只有不同时出现在navigation堆栈的情况下,才能使每个页面包含各自的MediaElement。否则,如果我们需要播放多个视频,那么我们需要复用同一个MediaElement,或者将不使用的MediaElement从element tree中移除。

2. 在将视频包含到应用程序时,确定其Build Action属性值设置为Content,而非Resource!

    这样做可以提高视频启动的性能。在视频文件作为资源嵌入时,在其播放前,应用程序会先对其进行加压缩,然后暂时存放到隔离存储空间(对于MediaElement使用的音频文件来说,也同样需要注意这个问题)。

3. 在MediaElement开始播放时,任何后台的音频播放(比如Zune播放的音乐)会暂停!

    这正是为什么MediaElement不被用于播放音效的主要原因。另外,即使视频文件中没有包含音频,这一点也是要注意的。

4. MediaElement在模拟器的light主题下存在Bug!

    这听上去很奇怪,但确实是事实。在模拟器上测试MediaElement,我们必须确保它在dark主题下运行。但是别担心,这个问题在真机中不存在。

5. MediaElement无法渲染完全不透明的效果!

    如果MediaElement中存在其他元素,我们可以通过视频清楚的看到它们,甚至是MediaElement的Opacity属性设置为1(该属性的默认值就是1)。这个是手机的media player(在其内部进行MediaElement的视频渲染)和Silverlight之间合成的异常。详见“Windows Phone支持的媒体文件格式”(链接为http://goo.gl/6NhuD),查看MediaElement支持的视频格式;以及“推荐的视频编码参数设置”(链接为http://goo.gl/ttPkO),查看哪种编码形式最合适我们的应用。如果我们正在使用Expression Encoder,就可以使用其中专门针对Windows Phone (和 Zune HD)平台已经预设值的参数来进行视频编码。

 

The User Interface

    除了简介页面以外(这里不作介绍),Subservient Cat应用程序使用了另一个页面,也就是主页面。主页面的的root grid包含了三个不同的用户控件,如图33.1所示。

1. 包含视频播放的 MediaElement元素

2. 一个简单的“intro screen”,介绍猫咪能够执行的指令,之后应用程序会播放命令相对应的视频片段。

3. 具有text box的panel,让用户猜测新的指令。

image

图33.1 主页面中三个主要的用户控件

注意:

视频播放时,手机处于横屏模式,所以它只是一个横屏模式的页面。但是,text box元素被用来给用户猜测新的指令,所以背后的代码暂时改变页面的SupportedOrientations属性值,使得焦点位于text box时,两种屏幕模式都可以使用。这样一来,具有硬件键盘的手机就可以让用户获得更好的体验。

应用程序栏具有三个按钮:一个用于展示指令输入面板,一个用于导航到简介页面,一个用于指示用户已经发现的指令数量(在背后代码中更新)。点击最后一个按钮还可以提示我们,是否有更多的指令等待我们去发现,因为对于我们用户来说,指令的总数,是一个谜。应用程序栏菜单是通过代码进行动态添加的,它包含了用户已经发现的指令清单,在用户点击其中任何一个指令时,猫咪就会做相应的动作。详见图33.2。

image

图33.2 应用程序栏菜单提供快速获取已发现的指令清单,例如“yawn”。

虽然应用程序可以播放不同的视频片段,但从性能的角度来看,事实上它使用了单个较长的视频文件(cat.wmv)。背后的代码会负责选择其中合适的视频片段进行播放。

通过CompositeTransform 来实现MediaElement的移动和扩大,因为“cat.wmv”源文件的头和尾具有一些我们不想看到的黑条。

MediaElement的Volume属性(值的范围为0~1)被设置为1(表示最大音量),因为其默认值是0.85。虽然播放的声音最大只能达到用户设置的值,但是这就确保了视频文件中的细节部分(短暂的“喵”叫声)也能够被听到。

注意:确保给MediaElement元素命名!

    如果我们没有给其命名,有可能marketplace发布审核流程不会发现你使用了MediaElement,因此就不会确保我们的应用程序具有“media library”能力,而这个能力对于本应用程序来说是必须的。

 

The Code-Behind

主页面的构造函数利用possibleCommands方法产生猫咪能够识别的指令集,该指令集伴随的声音用其在“cat.wmv”文件中的起始和终止时间表示。

在 OnNavigatedTo 事件处理中,使用之前已经发现的指令来填充应用程序栏菜单。这些指令存放在discoveredCommands中,而discoveredCommands又是作为一个设置保存起来。

为了在应用程序栏按钮图标中展示已经发现的指令数量,该应用程序工程中包含了一些图片,包括appbar.1.png、appbar.2.png和appbar.3.png等等。至于选用哪一个图片,就需要根据discoveredCommands集合的数量来确定。

在页面加载时,视频就自动开始播放(因为代码中的AutoPlay属性没有设置为false),但是我们不想播放整个视频来展示猫咪的所有动作。相反,我们只应该播放视频的前1.5秒。因此,在MediaElement的MediaOpened事件处理函数中(该事件在媒体文件加载并准备播放时触发),我们利用videoTimer在视频播放1.48秒以后进行暂停。该暂停在videoTimer的Tick事件处理函数“VideoTimer_Tick”中完成。

注意:直到MediaOpened事件触发,我们才能够在MediaElement中播放视频!

    在设置MediaElement的源文件后(在XAML或者背后代码中都可以完成),我们不能立即与媒体文件进行交互。相反,我们必须等待MediaOpened事件的触发。如果由于某些原因,媒体文件无法加载,那么MediaFailed事件就会被触发。Subservient Cat应用程序没有使用手动调用Play的方法,那是因为它使用了MediaElement的自动播放特性。但如果不使用其自动播放的特性,就必须在MediaElement_MediaOpened事件处理函数中调用Play方法。

注意:为什么在手机连接到PC机的Zune后,无法播放手机上的视频?

    这个原因其实在前一章中已经解释过。Zune是一个桌面应用程序,它会锁定手机的媒体库,这就导致了MediaElement无法加载媒体文件。记住,如果我们需要调试应用程序中视频播放相关的功能,可以使用Windows Phone Developer Tools 中提供的Windows Phone Connect Tool工具来连接手机,而不是通过Zune来连接。

    在Subservient Cat应用程序中,我们可以通过MediaFailed事件来检测这种情况。当然,我们假设这种情况的出现就是由于Zune的连接,因为对于应用程序来说,该视频文件就是本地的文件。

PlayClip方法可以使视频暂停,回到beginTime参数指定的起始时间点,重新初始化videoTimer,使得视频可以在endTime参数制定的终止时间停止播放。但是,由于设置MediaElement的Position会带来一些不友好的效果,如视频会快速前进或者快速回退到指定的时间点(而不是即刻的跳转),应用程序的简介页面已经对这种过渡进行了视频隐藏处理(我们不希望展示哪些有待用户发掘的视频片段)。Position的设置在BeginInvoke回调函数中完成,使得简介页面可以进行显示。如果不是这样做的话,我们就会看到不想要的情况出现。视频延时的长度设置为2秒,这段时间可以让用户在简介页面上浏览指令。我们没有办法获知用户真实消耗的时间,但2秒钟已经足够长的了。

注意:在我们设置MediaElement的Position参数后,效果无法即刻显现!

    相反,我们可以看到目标时间点之前或之后的一小段视频,就像那种看快进或者是快退的效果。因为Subservient Cat应用程序使用的方法是:暂时采用其他的元素来遮盖视频。

    在当前的Windows Phone版本中,MediaElement元素并不支持标记。使用标记来区分cat.wmv视频文件中单独的视频片段,这是一个理想的方案,而且还可以大幅度减少背后的处理代码。但是,使用DispatcherTimer来通知应用程序相关的视频已经播放完毕,这也是一个可替代的方案。下面是需要注意的两个事项:

1. 定时器的精度没有达到“帧”的级别。本应用程序使用的视频,在每个片段的最后使用了一些缓冲,以防videoTimer的Tick事件触发滞后。

2. 如果我们想要弹出一个消息框,视频文件会在后台继续播放,但是定时器的Tick事件处理不能被调用。无论视频播放多长时间,直到消息框解除才能恢复Tick事件处理(MessageBox.Show是一个阻塞的操作)。这正是为何在源代码中,首先使用DiscoveredButton_Click来暂停视频的播放。

    当我开始写Subservient Cat应用程序的时候,我在OnNavigatedFrom事件中调用了MediaElement的Stop方法,因为在简介页面显示,而主页面处于堆栈中时,我担心不必要的视频播放会引来性能的下降。但是,事实证明这种担心是多余的,因为在页面离开时,MediaElement会暂停所播放的视频。如果我们不需要这种特性(例如,在其他页面时,我还想听到视频播放的声音),我们必须将MediaElement附加到某个帧,而不是一个特定的页面。

MediaElement和隔离存储空间中的文件

    如果想要播放隔离存储空间中的文件(例如,我们的应用程序下载并将它保存在此处),我们可以调用MediaElement的SetSource方法,该方法以一个流为参数,而不是一个URI。有了它,我们就可以传入一个合适的IsolatedStorageFileStream。


本文转博客园博客,原文链接:

http://www.cnblogs.com/dearsj001/archive/2012/08/21/101App4WP7_SubservientCat.html

,如需转载请自行联系原作者


相关文章
|
4月前
|
Linux C++ Windows
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
|
1月前
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
44 11
|
4月前
|
Java 应用服务中间件 开发工具
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
|
4月前
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
|
4月前
|
PHP Windows
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
|
4月前
|
PHP 开发工具 git
【Azure 应用服务】在 App Service for Windows 中自定义 PHP 版本的方法
【Azure 应用服务】在 App Service for Windows 中自定义 PHP 版本的方法
|
4月前
|
网络安全 API 数据安全/隐私保护
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
|
4月前
|
Shell PHP Windows
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
|
4月前
|
存储 Linux Windows
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
【应用服务 App Service】App Service For Windows 如何挂载Storage Account File Share 示例
|
4月前
|
应用服务中间件 nginx Windows
【Azure 应用服务】在App Service for Windows中实现反向代理
【Azure 应用服务】在App Service for Windows中实现反向代理