Windows Phone

Windows Phone 视频捕获:最优方法

Chris Barker

下载代码示例

Windows Phone 7.1 SDK 开辟了一些新的开发领域,其中包括访问 Windows Phone 7.5 设备摄像头的能力。 Windows Phone 8 发布时带来了一些新的功能,如能够在支持的硬件上捕获高清晰度的 1080p 视频。 虽然 Windows Phone 7.1 SDK 可能已经过拓展而支持了一些新的设备功能,但 Windows Phone 8 版本亦同时经历了一场操作系统层面的体系结构变革——与 Windows 8 共享一个内核。 另一项重大变化是向 Windows 8 模型迁移了一系列 API,并采用了一种称作 Windows 运行时 (WinRT) 的开发人员界面。

Windows Phone 7.1 SDK 是以 Windows Phone 7.5 功能为开发目标的版本。 从此处开始,当我提及 Windows Phone 7.5 时,其意同时涵盖操作系统版本及 SDK。 (顺便提一句,Windows Phone 7.5 的代号是 Mango,Windows Phone 8 的代号是 Apollo——您可能已在别处见过这些名称。)

Windows 运行时不仅引入了若干跨 Windows Phone 和 Windows 8 的一致 API,还提供了一个更加高效的本机运行时,以允许使用相同的模型提供新的 Windows Phone 特有 API。 我不会去深究 Windows 运行时会带来哪些新的变化,但您应知道,它确实会影响到 API(比如实现视频捕获的那些)。

下面,我将概述这两个版本之间的差异,但您真正需要掌握的是如何维护自己的 Windows Phone 7.5 项目,同时为 Windows Phone 8 用户提供更丰富的体验。 本文提供了一个巨大的优势:所讨论的技术不只适用于视频捕获,还适用于其他所有针对 Windows Phone 8 而彻底改造过的 API。 我将使用现有的公共代码示例来帮助解释一些技术,您可以借助这些技术将代码重用引入自己的 Windows Phone 7.5 及 8 项目——甚至是 Windows 8 项目。

开始使用

我要阐述的主要目标之一是如何将某个解决方案移植到 Windows Phone 8,同时兼顾 Windows Phone 7.5 设备。 在正式开始之前,需要指出的一点是,在许多情况下,您根本不需要做任何事情。 您现有的 Windows Phone 7.5 应用程序会继续运行在 Windows Phone 8 上(虽然应该进行测试,以确保没有任何意外行为)。 将 Windows Phone 7.5 设为目标时,Visual Studio 2012 只允许您使用支持的 API。 另外,请记住,如果想使用任何新的 API 及其提供的功能,则只需关心为 Windows Phone 8 编写的代码。

我假设您需要继续支持 Windows Phone 7.5 用户,同时使 Windows Phone 8 用户能够访问其设备新增的丰富功能。

为了帮助解释如何实现最优的解决方案,我将使用 Windows Phone (7.5) 视频录制器示例 (bit.ly/16tM2c1) 作为起点。 请记住,虽然这里碰巧使用了视频录制器代码示例,但此处讨论的方法适用于需要跨平台版本的任意平台功能。

关于这个解决方案,有几点需要指出的是:

  • 它未采用“模型-视图-视图模型”(MVVM) 模式。
    • 大多数 UI 位于 MainPage.xaml 文件中。
    • 它将大部分逻辑从 MainPage.xaml.cs 代码隐藏文件中提取了出来。
  • 它使用 Windows Phone 7.5 API 来操作摄像头——名为 System.Windows.Media.VideoCaptureDevice 的类。 在这方面,Windows Phone 8 引入了一个新的 API,我会稍后详谈。

事实上,该解决方案未采用 MVVM 模式并没有什么大问题——这样做也很好(通常建议用于生产代码),因为它可以节省一些后期重构工作,其本身并不是一个兼容性问题。

但是,VideoCaptureDevice 类在迁移到 Windows Phone 8 时会产生一些限制。 它会在 Windows Phone 8 运行时上运行得很好,但无法提供最高性能,而且无法提供硬件支持的所有分辨率(除此之外,还有一些其他限制)。

在随后的章节中,我会采取以下方法:

  • 为在不同平台间有不同实现的功能创建一个共同抽象。 这让您能够共享使用该功能的代码。
  • 将视频录制器的抽象放入一个可移植类库 (PCL)。 这使得以后在需要的时候能更方便地向该 PCL 中迁移代码。
  • 通过文件链接共享 MainPage 的代码隐藏(该应用程序未采用 MVVM 模式,因此这个决定非常实用,否则我建议将视图模型移到一个 PCL 中)。

由于我比较贪心,想实现最优的方法,因此需要想办法将 Windows Phone 7.5 的摄像头逻辑从 MainPage.xaml.cs 文件中抽象出来。 我将在下一节中解决这个问题。

去耦合与抽象实现

首先,需要一个用于构建代码的地方。 类库虽然可以,但使用 PCL 可能会更好。 PCL 可以让您指定目标平台,并提供了一个很好的方式来限制您只使用平台交集提供的 API——最终让您有能力编写出跨项目的二进制引用(而不是简单的编译时针对目标平台链接和重新生成代码/项目)。 在这种情况下,可以创建以 Windows Phone 7.5(或更高版本)和 Windows Store 应用程序(即 Windows 8 的“现代应用程序”)为目标的 PCL 项目并将其命名为 VideoRecorder.Shared(见图 1)。

Configuring Your Portable Class Library
图 1 配置移植类库

按照该抽象模式 (bit.ly/YQwsVD),可以创建一个 VideoRecorderCore 抽象类,这可让您在必要时以平台特定代码为目标。 该抽象类如图 2 所示。

图 2 创建 VideoRecorderCore 抽象类

namespace VideoRecorder.Shared {   public abstract class VideoRecorderCore   {     public abstract void InitializeVideoRecorder();     public abstract void StartVideoRecording();     public abstract void StopVideoRecording();     public abstract void StartVideoPreview();     public abstract void DisposeVideoPlayer();     public abstract void DisposeVideoRecorder();     public static VideoRecorderCore Instance { get; set; }   } }

注:在图 2 所示的例子中,可以简单地使用一个接口,但在许多情况下,可能需要一些共同的基本功能。

在 sdkVideoRecorderCS 项目中,理想情况是花些时间实现 MVVM 模式,但这留待他日再讲。 现在的重构重点是为该抽象类提供一个具体实现。 幸运的是,已经有具体实现了——它现在只是在 MainPage.xaml.cs 中耦合得有点紧罢了。 为了解决这个问题,可以在 sdkVideoRecorderCS 项目中创建一个 WP7VideoRecorder 类,并在 PCL 项目中从 VideoRecorderCore 继承它。 接下来,需要做的是将该实现从 MainPage.xaml.cs 中移出并放进适当的重载方法。 作为示例,InitializeVideoRecorder 方法最初如图 3 所示。

图 3 InitializeVideoRecorder 方法

public override void InitializeVideoRecorder() {   if (captureSource == null)   {     captureSource = new CaptureSource();     fileSink = new FileSink();     videoCaptureDevice =        CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();     captureSource.CaptureFailed +=     new EventHandler<ExceptionRoutedEventArgs>(OnCaptureFailed);     if (videoCaptureDevice != null)     {       videoRecorderBrush = new VideoBrush();       videoRecorderBrush.SetSource(captureSource);       viewfinderRectangle.Fill = videoRecorderBrush;       captureSource.Start();       UpdateUI(ButtonState.Initialized, "Tap record to start recording...");     }     else     {       UpdateUI(ButtonState.CameraNotSupported,          "A camera is not supported on this device.");     }   } }

我不会在此逐行讨论图 3 中的代码(该文档 (bit.ly/YVIf0I) 讲解得非常全面),但简要地说一下,这段代码的功能是初始化 VideoCaptureDevice 实例,然后在 UI 中设置视频预览。 我只是简单地将代码从代码隐藏复制粘贴到了具体实现中,因而在这里引入了一些问题。 该代码引用了 UI 元素和方法(例如,viewfinderRectangle 和 UpdateUI 方法)。 您的具体实现中不需要这些,如果引入了视图模型,则更容易将它们分离出来。 所以,这里需要一点点的清理工作:

  1. 将 UI 代码移回到各自的 UI 方法中(就本例而言,是指 MainPage.xaml.cs 文件中的 InitializeVideoRecorder)。
  2. 为初始化 VideoRecorderBrush 创建一个新的抽象方法,因为跨 Windows Phone 7.5 和 Windows Phone 8 需要这样做——但实现可能会有所不同。

做完部分清理工作后,您的方法可能类似下面这样:

public override void InitializeVideoRecorder() {   if (_captureSource == null)   {     _captureSource = new CaptureSource();     _fileSink = new FileSink();     _videoCaptureDevice =        CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();     _captureSource.CaptureFailed +=        new EventHandler<ExceptionRoutedEventArgs>(OnCaptureFailed);    } }

现在,您能够获得 Windows Phone 代码隐藏 (MainPage.xaml.cs) 的好处——跨 Windows Phone 7.5 和 Windows Phone 8 版本可用,如图 4 所示。

图 4 可在 Windows Phone 7.5 和 Windows Phone 8 中使用的代码隐藏

public void InitializeVideoRecorder() {   _videoRecorder.InitializeVideoRecorder();   _videoRecorder.CaptureFailed += OnCaptureFailed;   if (_videoRecorder.VideoCaptureDevice != null)   {     videoRecorderBrush = new VideoBrush();     videoRecorderBrush.SetSource(       _videoRecorder.VideoSource as CaptureSource);     viewfinderRectangle.Fill = videoRecorderBrush;     _videoRecorder.StartVideoSource();     UpdateUI(ButtonState.Initialized, "Tap record to start recording...");   }   else   {     UpdateUI(ButtonState.CameraNotSupported,        "A camera is not supported on this device.");   } }

所有要做的工作只是初始化 VideoRecorder 实例,接着就可以开始使用新的平台特定实现了:

_videoRecorder = VideoRecorderCore.Instance = new WP7VideoRecorder();

除了一些小的改动,您可以按照类似的方式继续重构其他方法。

面向新的 Windows Phone 8 API

正如前面摘要中所说的那样,将 Windows Phone 7.5 代码移植到 Windows Phone 8 只需要一些很细微的改动(所要做的不过是打开项目,然后选择“升级到 Windows Phone 8.0”罢了(见图 5)),但如果需要维护两个版本呢? 完成刚刚采取的那些步骤后,代码现在的组织方式可轻松支持代码重用。 除此以外,由于已对视频录制器执行了去耦合操作,因此,您将能够使用新的、更加强大的 WinRT API(用于 Windows Phone 8 上的视频摄像头捕获)。

Upgrading Your Project to Target the Windows Phone 8 Runtime
图 5 升级项目以面向 Windows Phone 8 运行时

下一步是创建 Windows Phone 8 项目,重用尽可能多的代码,并引入所需的任意新功能。

在创建 Windows Phone 8 版本这一点上,您有两个选择。 制作一份现有项目的副本并对其进行升级,或从头开始创建一个新的 Windows Phone 8 项目并加入重复的代码文件和引用。 如何决定取决于项目的大小和需要重用的代码的多少。 在本示例中,我们将制作一份项目副本并进行升级——这意味着您需要精选要重用的部分,以降低缺少某些关键文件的可能。 需要完成的工作如下:

  • 复制 sdkVideoRecorderCS 项目,并将 sdkVideoRecorderCS.csproj 重命名为 sdkVideoRecorderCS.WP8.csproj。 接下来,将新项目添加到现有解决方案中,以方便维护这两个版本。
  • 将新项目升级到 Windows Phone 8。 您会发现,升级后的项目无需任何进一步的修改即可在 Windows Phone 8 上顺利运行——这得归功于 API 的向后兼容性。 这样做的优点是无需更改任何代码,但缺点是性能下降——而且无法使用该平台最新和最棒的功能。
  • 现在,我们开始挑选需要重用的元素。 例如,MainPage.xaml 和 MainPage.xaml.cs 中的大部分将在两个版本间保持一致(至少在该解决方案中是这样),因此在 Windows Phone 8 项目中删除这些文件的现有版本,并在 Windows Phone 7.5 项目中添加这些版本的文件链接:右键单击项目,选择“添加现有项目”,然后指向 MainPage.xaml 文件并选中“添加为链接”(见图 6)。

Adding a File Link
图 6 添加文件链接

注:除了刚才介绍的那样用菜单操作外,也可在按住 Ctrl+Shift 的同时,简单地将 MainPage.xaml 文件从一个项目拖放到目标项目。 这会在创建文件链接的同时自动移动代码隐藏文件。

需要对所有相关文件重复上述步骤,但出于演示目的,这是现在唯一一个需要添加和重用的文件链接。

另外简单提一句,当谈及代码重用时,我们总是抱持美好的幻想,但在现实世界中,当我们需要跨平台使用相同代码时,总会有一、两处细微差异。 对于这种情况,维护两套代码是不切实际的,而把代码中的平台特定部分抽象出来又有点小题大做。 这时,使用预处理器指令分离特定平台的特定代码行通常会更好些。 我们稍后会提供一个示例,但重要的是不要滥用这一技术,否则您的代码会很快变成“意大利面条”。

使用平台抽象的一个好时机是当存在具有平台差异的孤立功能块时。 在当前示例中,这一孤立功能块就是实际的视频录制器逻辑。 在当前的 Windows Phone 8 项目中,有一个工作良好的 WP7VideoRecorder.cs 文件,但它未使用新的 Windows Phone 8 API,因此,这就是需要更改的地方。 从 Windows Phone 8 项目中删除 WP7VideoRecorder.cs 文件,然后创建一个名为 WP8VideoRecorder.cs(亦继承自 VideoRecorderCore)的新文件。

像之前那样实现每个方法。 这次的关键差异在于我们将使用 Windows.Phone.Media.Capture 命名空间而非 System.Windows.Media namespace。 前者是较新的 WinRT 命名空间,它引入了一个名为 AudioVideoCaptureDevice 的类。 其用途与之前使用的 VideoCaptureDevice 类相似,但相比之下,其功能要丰富许多。

WinRT API 采用了若干不同于之前 API 的方法。 我们很快就会碰到一个:许多 API 是异步的(稍后详谈)。 另一个差异是需要使用 Windows.Storage 命名空间而不是使用熟悉的 System.IO.IsolatedFileStream 处理存储(尽管后者仍将用于支持媒体播放)。

我现在将简述几处较大的更改,以指明这个视频录制器方案中的一些差异之处,以及您在维护某个代码重用元素时将如何以更为普适的方法解决此类差异。

Windows Phone 7.5 版本的视频录制器代码中定义了若干私有变量:

private CaptureSource _captureSource; private VideoCaptureDevice _videoCaptureDevice; private IsolatedStorageFileStream _isoVideoFile; private FileSink _fileSink; private string _isoVideoFileName = "CameraMovie.mp4";

理想情况下,使这两种基本代码越相似越好,但新 API 中不需要 CaptureSource 或 FileSink——CaptureSource 已被实际的 VideoCaptureDevice 实例取代,该实例可作为源使用,可直接提供 FileSink 的功能,因此,我们只需要一个 StorageFile 作为其保存位置:

private AudioVideoCaptureDevice _videoCaptureDevice; private IsolatedStorageFileStream _isoVideoFile; private StorageFile sfVideoFile; private string _isoVideoFileName = "CameraMovie.mp4";

接下来的逻辑步骤是完成这些方法的具体实现。 我将再次从 Initialize­VideoRecorder 开始。 您已见过该方法之前的模样,此处只需以相似方式实例化 AudioVideoCaptureDevice 实例即可:

public async override void InitializeVideoRecorder() {   CameraSensorLocation location = CameraSensorLocation.Back;   var captureResolutions =      AudioVideoCaptureDevice.GetAvailableCaptureResolutions(location);   _videoCaptureDevice =      await AudioVideoCaptureDevice.OpenAsync(location, captureResolutions[0]);   _videoCaptureDevice.RecordingFailed += OnCaptureFailed; }

正如您看到的那样,语法不同,但代码的用途相同。 此外,这段代码还允许您配置其他摄像头属性,如指定捕获分辨率和要使用的摄像头(如果有多个摄像头可用的话)。 此处您对分辨率的控制已优于 Windows Phone 7.5 API 所提供的,因为您可以使用原尺寸、高清晰度的 1080p(如果手机摄像头支持的话)。 另一个值得称道的差异是:这些方法是异步的(许多 WinRT API 都是这样)。 为增强可管理性,可以引入 C# 5 的关键字 async 和 await。 这些功能在别处已有说明,此处不再赘述,但它们可帮助您获得异步代码的优势,同时降低这样做的复杂度。

下一个要讨论的是 InitializeFileSink 方法。 虽然不再需要 FileSink 本身,但我们仍需要初始化用于存储视频捕获的文件。 在开始使用 Windows.Storage 命名空间及 StorageFolder 和 StorageFile 等类的地方,也需要这样做:

public async override void InitializeFileSink() {   StorageFolder isoStore = ApplicationData.Current.LocalFolder;   sfVideoFile = await isoStore.CreateFileAsync(     _isoVideoFileName, CreationCollisionOption.ReplaceExisting); }

我们不会把每个方法都讲一遍,因为这些才是真正需要强调的重大差异。 对于跨两个版本保持一致的方法,可将其移入 VideoRecorderCore 基类,以确保子类具有相同的行为。

完成其余更改后,您会遇到与下面一行有关的生成错误:

_videoRecorder = VideoRecorderCore.Instance = new WP7VideoRecorder();

原因很明显——Windows Phone 8 代码引用了一个不存在的类:WP7VideoRecorder。 您当然需要引用新的 WP8VideoRecorder 类,但在 MainPage.xaml.cs 文件中作此更改会破坏 Windows Phone 7.5 代码(因为它们也需要链接这个文件)。

会为您提供一些选项。 可以使用类似下面的预处理器指令:

#if WP7   _videoRecorder = VideoRecorderCore.Instance = new WP7VideoRecorder(); #else   _videoRecorder = VideoRecorderCore.Instance = new WP8VideoRecorder(); #endif

使用预处理器指令时,一个条理更加分明的做法是将这些移到包装类中——例如,在 VideoRecorderCore 抽象基类中引入一个 CreateVideoRecorder 方法,并将前面的 #if 声明放置在该方法中。

此处我们采取的路线是避免使用预处理器指令,而是将实际类别查找抽象到一个独立的工厂类中——这意味着使用该 recorder 的代码将在 Windows Phone 7.5 和 Windows Phone 8 中保持一致:

_videoRecorder =   VideoRecorderCore.Instance = VideoRecorderFactory.CreateVideoRecorder();

另一种做法是使用依存关系注入 (DI) 或服务定位器模式,并将该实例解析留给相应的容器或服务去完成。

一个更为隐蔽的问题是为摄像头预览设置 VideoBrush。 在这种情况下,仍可考虑采用加入预处理器指令 #if 这一技术来区分微小的实现细节:

#if WP7   videoRecorderBrush.SetSource(_videoRecorder.VideoSource as CaptureSource); #else   videoRecorderBrush.SetSource(_videoRecorder.VideoSource); #endif

这样做的原因是 Windows Phone 8 重载了 SetSource 方法,以允许将某个对象指定为 Source 对象。 正因如此,您才能在 Windows Phone 8 的 VideoSource 属性中返回 AudioVideoCaptureDevice 实例。 要支持这一做法,需要向 Windows Phone 7.5 项目中添加新的“WP7”条件编译符号(在“项目属性”|“生成”下添加,见图 7)。

Adding a Custom Conditional Compilation Symbol to Your Windows Phone 7.5 Project
图 7 向 Windows Phone 7.5 项目添加自定义条件编译符号

正如前面提到的那样,Windows 运行时非常依赖异步方法,以提高应用程序的响应度,但是,如果我们需要跨平台版本共享代码,这会产生哪些影响? 虽然可以在 Windows Phone 7.5 项目中编写 C# 5 代码,但在使用 async 和 await 关键字时,会有特定实现细节不可用。 请考虑以下方法:

public async override void InitializeVideoRecorder() {   CameraSensorLocation location = CameraSensorLocation.Back;   var captureResolutions =      AudioVideoCaptureDevice.GetAvailableCaptureResolutions(location);   _videoCaptureDevice =      await AudioVideoCaptureDevice.OpenAsync(location, captureResolutions[0]);   _videoCaptureDevice.RecordingFailed += OnCaptureFailed; }

这实际上等于是设置 VideoCaptureDevice 属性,但使用代码类似下面这样:

_videoRecorder.InitializeVideoRecorder(); if (_videoRecorder.VideoCaptureDevice != null) {   ...
} else {   UpdateUI(ButtonState.CameraNotSupported,      "A camera is not supported on this device."); }

虽然看起来可能不太明显,但在等待对 AudioVideoCaptureDevice.OpenAsync 方法的调用时,对 _videoRecorder.VideoCaptureDevice 的检查可能已经完成。 换句话说,VideoCaptureDevice 检查的求值结果可能为 NULL,这是因为 VideoCaptureDevice 还没来得及初始化。

同样,在这个阶段,您有下述几个选择。 将使用代码改为异步模式可能只需改动少量代码——但对于某些解决方案,可能会有很多工作要做。 要避免这个问题,可以简单地将异步代码包装到一个异步包装方法中。 另一种做法是采用一种基于事件的机制在完成初始化时通知使用者。

也许您正想借此机会转向新的异步模型,因此等待 InitializeVideoRecorder 调用,但如果 Windows Phone 7.5 SDK 不支持所需的结构,又该如何? 解决方案之一是在 Visual Studio 中下载“Async for .NET Framework 4, Silverlight 4 and 5, and Windows Phone 7.5”NuGet 包,如图 8 所示。

Find the Async NuGet Package for Windows Phone 7.5 by Searching for “microsoft.bcl.async”
图 8 通过搜索“microsoft.bcl.async”查找用于 Windows Phone 7.5 的 Async NuGet 包

在撰写本文时,该包仍处于预发布阶段,但预计不久就会发布稳定版本。 如果想走更为稳妥的路线,则需要按照前面讲述的方法重写代码并引入事件模式或异步包装。

注:请务必安装 2.1 或更高版本的 NuGet Package Manager,否则在尝试使用该包时会遇到意外错误消息。 可以从 bit.ly/dUeqlu 下载最新版本。

下载该包后,可以对每个项目中的代码进行调整。 例如,可通过返回 Task 类型而非 void 来使抽象基类支持异步——这会使您等待结果而非采用现在的“发后不理”机制。 另外,在异步方法名称中附加“Async”也是个良好的惯例,这可使方法的使用对开发人员来说更为直观。 例如,某些方法现在会包含签名,类似下面这样:

public abstract Task InitializeVideoRecorderAsync(); public abstract Task InitializeFileSinkAsync();

当然,在这之后,需要重构子类中的代码。 例如,

public override async Task InitializeVideoRecorderAsync() {

最后,更新 MainPage.xaml.cs 代码,以支持在异步操作时等待的能力。 如下例所示:

public async void InitializeVideoRecorder() {   await _videoRecorder.InitializeVideoRecorderAsync();

完成这些最后的更改之后,您会发现 Windows Phone 7.5 和 Windows Phone 8 项目现在都能成功运行了。 您有了强大的代码重用元素,且使用的是其能够支持的最新功能。 您实现了最优的解决方案!

关于 Windows 8

跟我打交道的许多合作伙伴都是采用 XAML 和 C# 开发 Windows Phone 应用程序的。 在考虑为 Windows 8 开发 Windows 商店应用程序时,他们的遇到的第一个技术难题是:应该走 HTML5/JavaScript 路线还是 XAML/C# 路线。 体系结构规划优良的 Windows Phone 解决方案能够提供大量可用于 Windows 8 的重用代码,因此,在选择将采用何种语言开发 Windows 商店应用程序时,这会是一个决定性因素。

虽然可在 Windows Phone 7.5 和 Windows 8 之间重用代码,但还是会有一些情况让您不得不在两者中选择其一。 视频录制器就是这样一个例子,但值得高兴的是,之前采取的做法可为您节省大量时间和工作。

实现该代码的 Windows 8 版本作为练习留给读者完成,如果您打算做此练习,可下载附带示例(包含在论述 Windows 8 解决方案时讨论的所有代码)。

注:对于 Windows 8 实现,需要使用 Windows.Media.Capture.MediaCapture 类。

进一步深入了解 MVVM

您刚刚的做法可为两个版本的 Windows Phone 提供 100% 可重用的 MainPage.xaml。 再加上之前提到的抽象和重构步骤,您还能获得接近 100% 可重用的随附代码隐藏文件。 如果引入 MVVM 模式的话,还可进一步提高这些技术的效用,而且,这还有助于提供大量重用代码(不仅适用于 Windows Phone 版本,还将包括 Windows 8 基本代码)。

这些技术不仅可在抽象出平台特定功能(例如前面介绍过的视频捕获功能)时实现代码重用,还可用于应用程序生命周期管理 (ALM)、文件存储等方面。

Chris Barker 是 Microsoft 的技术推广人员,长驻英国 Derbyshire 郡。他不仅为独立软件供应商和企业组织开发代码多年,运营着多家性能和可扩展性实验室,同时还对底层调试技术抱有浓厚的兴趣。近年来,他更加关注于使用 XAML 和 C# 进行客户端开发,现在与全球消费者合作伙伴合作开展 Windows 8 和 Windows Phone 平台的开发工作。

衷心感谢以下技术专家对本文的审阅:Daniel Plaisted (Microsoft)
自 2008 年加入 Microsoft 以来,Daniel Plaisted 参加了用于 Windows 商店应用程序的托管可扩展性框架 (MEF)、可移植类库 (PCL) 和 Microsoft .NET Framework 方面的工作。 他曾出席 MS TechEd、BUILD 及各种本地组、代码活动和会议。 业余时间,他喜欢计算机游戏、阅读、徒步旅行、杂耍和花式沙包。他的博客是 blogs.msdn.com/b/dsplaisted/