将您的云服务与文件选取器合约相集成

过去,用户都是在本地 PC 上整理、共享和维护他们的文档、照片、视频和音乐。但云的出现很快为用户提供了更加丰富的方式来访问、使用和管理他们的重要文件。Windows 8 综合考虑了这些新的应用场景,让您能够直接将云服务直接集成到您的应用程序中,从而塑造前所未有的全新体验,实现一种全新的可能。

您可以看到,使用文件选取器合约的 SkyDrive 应用程序中突显了许多此类应用场景。文件选取器合约旨在使用户存储在您的应用程序中的文档、照片、视频和音乐可以供所有其他 Windows 8 应用程序访问。在本篇博文中,我们使用已按照借助 SkyDrive 和 Windows 8 将您的应用程序、文件、PC 和设备连接到云中的说明实施全部三种文件选取器合约的 SkyDrive 应用程序来向您展示:

  • 什么是文件选取器合约以及您如何利用它们来为您的应用程序塑造一系列全新的体验
  • 如何为您的应用程序挑选适用的文件选取器合约
  • 实施文件选取器合约的技巧和窍门

SkyDrive 应用程序中的文件打开选取器支持

SkyDrive 应用程序中的文件打开选取器支持

文件选取器合约概述

顾名思义,文件选取器合约是对文件选取器的扩展,允许 Windows 8 应用程序向所有其他 Windows 8 应用程序提供文件、保存位置甚至文件更新。例如,就像您在刚才的屏幕截图中所看到的,我在 SkyDrive 上的所有文件都可以在文件选取器内访问。

文件选取器合约包含三种独立的合约:文件打开选取器、文件保存选取器和缓存文件更新程序。您只需要实施适用于您的应用程序的合约即可。在考虑实施哪些合约时,可以将以下内容作为指导:

  • 文件打开选取器: 如果您的应用程序提供独有和/或重要的文件视图,通过其他方式不易访问时,可以使用此合约。例如,SkyDrive 应用程序实施此合约后,即可向所有 Windows 8 应用程序提供对存储在其服务中的文件的访问权限。
  • 文件保存选取器: 如果您的应用程序支持文件打开选取器合约,那么当用户还希望能将您的应用程序用作保存位置时,可以使用此合约。例如,SkyDrive 应用程序实施此合约后,用户就能够从任何 Windows 8 应用程序轻松保存到其服务中。对于某些应用程序,您需要确定是实施文件保存选取器还是共享目标,或是同时实施这两者来将数据移至您的应用程序。共享和交换数据主题文章可以为您提供一些建议。
  • 缓存文件更新程序: 当您的应用程序还需要自动跟踪和更新文件以与应用程序的中央存储器保持同步时,使用此合约。SkyDrive 应用程序通过实施此合约,可确保选取/保存到 SkyDrive 应用程序的任何文件都可以轻松进行更新或刷新,从而使用户免去通过文件选取器执行操作的麻烦。例如,我可以使用我喜欢的照片应用程序打开 SkyDrive 上的照片,而且我对照片所做的任何更改都会自动发送回 SkyDrive(而不需要再通过文件选取器)。

最好将这些合约看作是递进关系。例如,我们建议 Windows 8 应用程序首先实施文件打开选取器合约,然后再决定是否适合实施文件保存选取器合约,以此类推。

 

文件选取器合约的递进关系

文件选取器合约的递进关系

现在您已经对合约有了大致的了解,我们来详细了解一下如何实施各个合约。为了便于说明概念,我们将仍以 SkyDrive 应用程序为例。

应用场景 1:文件打开选取器合约

文件打开选取器合约为用户提供了一种方式,使用户可以在其他 Windows 8 应用程序中使用他们在您的应用程序内存储、创建和管理的文件。例如,通过实施文件打开选取器合约的 SkyDrive 应用程序,我就能够从其他任何 Windows 8 应用程序访问我在 SkyDrive 上的所有文件。从设置我的用户头像到打开 SkyDrive 上的一个文档,我在 SkyDrive 上的所有内容都可以轻松访问,而不论我执行什么操作,也不论我使用的是什么 Windows 8 应用程序!

如果您的应用程序实施此合约,它将在文件选取器的打开模式中启动和显示。每当用户选取您的应用程序所提供的文件类型时,文件选取器菜单中就将显示您的应用程序的入口点:

文件打开选取器

SkyDrive 显示在文件选取器菜单中

当启动时,您的应用程序会位于文件选取器的视图区域中,而且文件选取器框架会采用您在清单中指定的配色方案:

skydrive_thailand

通过文件打开选取器合约托管在文件选取器中的 SkyDrive 应用程序

实施合约

要将文件打开选取器合约集成到您的应用程序,请参考快速入门。当您的应用程序集成合约之后,下一步就是设置您的应用程序,以显示可供用户选取的文件。在将文件打开选取器合约添加到您的清单之后,您可以使用内置的 Visual Studio 模板来构建选取视图。或者,如果您已经在主应用程序中构建了视图,则可以将此用作您的选取视图的基础。如下图所示,SkyDrive 仍然使用主应用程序中现有的视图,这不仅节省时间,而且可以与主应用程序视图保持一致。

skydrive_view1SkyDrive 应用程序提供相似的视图和导航模式

SkyDrive 应用程序的主版本和托管版本提供相似的视图和导航模式

另外,鉴于用户将会在您的应用程序中选择文件,您的应用程序应提供一种选择机制,这一点非常重要。如果您已经在使用内置的 HTML ListViewXAML GridView 控件,那么选择技术和视图应该已经内置到了控件中。

SkyDrive 应用程序中的选择视图

SkyDrive 应用程序中的选择视图

用户选择文件后,您需要向文件选取器传递一个 StorageFile,以使其能够显示在文件选取器 Basket 中。根据您的应用场景,您可以使用基于本地的 StorageFile,也可以使用基于 URIStream 的 StorageFile。基于 URI 和 Stream 的 StorageFile 最适用于位于本地计算机之外的其他位置的文件,因为此类 StorageFile 允许将文件下载推迟到使用文件的应用程序访问文件时再进行。选择使用哪种 StorageFile 取决于您的应用程序的实施方式,URI 是一种无需干预的自动方式,而基于 Stream 的方式则允许您配置当文件被访问时下载文件的方式。例如,如果文件不能通过 URI 公开访问,并且要求身份验证表单,则基于 Stream 的解决方案会允许必要的凭据通过。下面是将基于 URI 的 StorageFile 添加到文件选取器 Basket 的简单示例:

JavaScript

 // Create thumbnail for the file
var thumbnailSource = Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri
(selectedItem.fileThumbnailUri));
 // Add a file to the FileOpenPickerUI that is downloaded using BackgroundTransfer

Windows.Storage.StorageFile.createStreamedFileAsync(selectedItem.name, onDataRequested, thumbnailSource).done
(function (streamedFile) {   pickerUI.addFile(selectedItem.id, streamedFile);
});


function onDataRequested(outputStream) {
   var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
   var download = downloader.createDownload(new Windows.Foundation.Uri(selectedItem.fileUri), null);
   download.startAsync().done();
   var inputStream = download.getResultStreamAt(0);
   Windows.Storage.Streams.RandomAccessStream.copyAndCloseAsync(inputStream, outputStream).done(function () {
      inputStream.close();
   });
}

C#

 // Create thumbnail for the file
var thumbnailSource = RandomAccessStreamReference.CreateFromUri(new Uri(selectedItem.FileThumbnailUri));
// Add a file to the FileOpenPickerUI that is downloaded using BackgroundTransfer
StorageFile file = await StorageFile.CreateStreamedFileAsync(selectedItem.Name, OnDataRequested, thumbnailSource);
_openUI.AddFile(selectedItem.Id, file);

protected async void OnDataRequested(StreamedFileDataRequest outputStream)
{
   var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
   var download = downloader.CreateDownload(new Uri(_selectedItem.FileUri), null);
   var downloadTask = download.StartAsync();
   using (var inputStream = download.GetResultStreamAt(0))
   {
      await RandomAccessStream.CopyAndCloseAsync(inputStream, outputStream);
   }
   await downloadTask;
}

打造选取用户体验

订阅文件打开选取器合约的一个重要部分是提供量身定制的选取体验,以选取为重心,并且与您的主应用程序的设计和个性化风格一致。文件选取器合约指南和清单规定了设计这种体验时需要重点关注的主要方面。

至于实施,下面提供的几种便捷方式可以确保轻松遵循指南:

  • 命令: 由于文件选取器中不支持应用栏,请使用 Visual Studio 模板中提供的内置命令行。由下图中的编号 1 展示。
  • 导航: 使您的导航模式和功能布局与主应用程序中的现状保持一致。此外,确保您设置 Title 属性内容的方式与您在应用程序中显示当前位置的方式一致。由下图中的编号 2 展示。
  • 选择: 由于文件选取器同时支持单选和多选,请使用 SelectionMode 属性来确定您的应用程序是否应该支持选择多个文件。由下图中的编号 3 展示。
  • 视图筛选: 使用 AllowedFileTypes 属性来筛选视图,仅显示用户可以选取的文件类型。
  • 启动: 使用 SettingsIdentifier 属性启动您的应用程序,使其返回用户上次从您的应用程序中进行选取时导航到的位置。
  • 身份验证: 如有必要,允许用户使用与登录您的主应用程序一致的方式登录您的应用程序。
  • 组织: 组织和显示文件,以针对浏览内容进行优化。如有可能,请尽量使用语义式缩放和轻型筛选器,而避免使用更重型的功能(如搜索)。

实施了文件打开选取器合约的 SkyDrive 应用程序用户界面概览

实施了文件打开选取器合约的 SkyDrive 应用程序用户界面概览

端到端的工作流

综合来看,下面是端到端的文件打开选取器工作流概览。在该图中,实施了文件打开选取器合约的应用程序(如 SkyDrive)标记为“提供应用程序”。

端到端的文件打开选取器工作流

应用场景 2:文件保存选取器合约

文件保存选取器合约允许您的应用程序作为 Windows 8 应用程序的保存位置。例如,SkyDrive 应用程序实施文件保存选取器合约后,我就能够直接从其他任何 Windows 8 应用程序将文件保存到 SkyDrive。如此,我无需离开当前所使用的应用程序就可以向 SkyDrive 中添加文件,还可以向 SkyDrive 中存储 SkyDrive 应用程序自身可能无法访问的文件(因为 SkyDrive 可能无权访问某个特定应用程序用于存储文件的位置)。

正如前面所说的,考虑实施文件保存选取器合约时,您的应用程序必须已经实施了文件打开选取器合约,这样可以确保用户能够从他们可以保存到的相同位置中进行选取。

将文件保存选取器合约集成到您的应用程序中后,您的应用程序就可以在文件选取器的保存模式中启动和显示。每当用户保存您的应用程序支持的文件类型时,文件选取器菜单中就将显示您的应用程序的入口点。与文件打开选取器合约类似,您的应用程序启动后将显示在文件选取器的视图区域中:

通过文件保存选取器合约托管在文件选取器中的 SkyDrive 应用程序

通过文件保存选取器合约托管在文件选取器中的 SkyDrive 应用程序

实施合约

由于您已经实施了文件打开选取器合约,文件保存选取器合约的实施方式与此非常类似(都参考相同的快速入门指南)。第一步是设置您的应用程序,以显示用户可以保存到的位置。仍然使用为文件打开选取器合约所构建的视图既可以节省时间,还可以与其他应用程序视图保持一致。事实上,完成这一步的最简单方式是直接重新使用您的文件打开选取器视图并删除 Basket 代码。

skydrive_documents

将主应用程序视图用于文件保存选取器的 SkyDrive 应用程序

用户保存文件后(您将收到 TargetFileRequested 事件),请验证文件名和扩展名(使用 FileName 属性),以确保它对您的应用程序来说是有效的。如果无效,则您可以按照 UX 指南的说明向用户显示一个错误。如果有效,您可以创建一个新的 StorageFile,并将其传回文件选取器,后者又会将其传递给写入内容的应用程序(即调用文件选取器的应用程序)。下面这段简单的代码阐释了这一概念:

JavaScript

 function onTargetFileRequested (e) {
   var request = e.request;
   var deferral = e.request.getDeferral();
   if (doesfileExist(saveUI.fileName)) {
      var dialog = new Windows.UI.Popups.MessageDialog("The location already has a file named " + saveUI.fileName + ".", "Replace the existing file?");
      dialog.commands.append(new Windows.UI.Popups.UICommand("Replace", function () {
         createFileAndFinishRequest(request, deferral)
      }));
      dialog.commands.append(new Windows.UI.Popups.UICommand("Cancel", function () {
         // Cancel save by setting targetFile to null
         request.targetFile = null;
         deferral.complete();
      }));
      dialog.showAsync().done();
   } else {
      createFileAndFinishRequest(request, deferral);
   }
}
function createFileAndFinishRequest(request, deferral) {
   _currentLocalFolder.createFileAsync(saveUI.fileName, Windows.Storage.CreationCollisionOption.replaceExisting).done
(function (newFile) {
      // Return the empty placeholder file so the calling app can add the file contents
      request.targetFile = newFile;
      deferral.complete();
   });
}

C#

 async void OnTargetFileRequested(FileSavePickerUI sender, TargetFileRequestedEventArgs args)
{
   var request = args.Request;
   var deferral = request.GetDeferral();
   if (DoesFileExist(_saveUI.FileName))
   {
      var dialog = new MessageDialog("The location already has a file named " + _saveUI.FileName + ".", "Replace 
 the existing file?");     dialog.Commands.Add(new UICommand("Replace", (command) =>
      {
         CreateFileAndFinishRequest(request, deferral);
      }));
      dialog.Commands.Add(new UICommand("Cancel", (command) =>
      {
         request.TargetFile = null;
         deferral.Complete();
      }));
      await dialog.ShowAsync();
   }
   else
   {
      CreateFileAndFinishRequest(request, deferral);
   }
}
async void CreateFileAndFinishRequest(TargetFileRequest request, TargetFileRequestDeferral deferral)
{
   request.TargetFile = await _currentFolder.CreateFileAsync(_fileSavePickerUI.FileName, CreationCollisionOption.
ReplaceExisting);   deferral.Complete();
}

打造保存用户体验

与文件打开选取器合约类似,订阅文件保存选取器合约的一个重要部分是提供量身定制的保存体验,以保存为重心,并且与您的主应用程序的设计和个性化风格一致。下面提供的几种便捷方式可以确保使您的文件保存选取器合约的实施遵循指南

  • 筛选视图: 如果用户更改文件选取器文件类型列表中的文件类型(FileNameChanged 事件),则更新您的视图以仅显示与选定文件类型相匹配的文件。由下图中的编号 1 展示。
  • 错误处理: 确保文件名、文件类型和用户要保存到的位置都有效。如果无效,显示一条错误并允许用户修复问题。使用与主应用程序相同的样式和个性化风格(应该已经满足了错误指南的要求)显示错误。由下图中的编号 2 展示。
  • 文件名: 当用户在您的保存页面中选择某个文件时,自动填充文件名(通过 TrySetFileName 方法)。由下图中的编号 3 展示。

实施了文件保存选取器合约的 SkyDrive 应用程序 UX 概览

实施了文件保存选取器合约的 SkyDrive 应用程序 UX 概览

端到端的工作流

综合来看,下面是端到端的文件保存选取器工作流概览。与文件打开选取器的图类似,实施了文件选取器合约的应用程序(如 SkyDrive)标记为“提供应用程序”。

端到端的文件保存选取器工作流概览

应用场景 3:缓存文件更新程序合约

通过缓存文件更新程序合约,当其他 Windows 8 应用程序更新您所维护的文件时,您的应用程序可以使文件保持最新。这意味着什么?我们再来看看 SkyDrive 应用程序。SkyDrive 在实施缓存文件更新程序合约后,就可以确保我所使用的任何文件(位于 SkyDrive 上)始终保持最新,并且我做的所有更改都可以上传到 SkyDrive。假设我正在使用我喜欢的照片编辑应用程序,我想要去除存储在 SkyDrive 上的某张照片中的红眼。在照片编辑应用程序中,我打开文件选取器,并从 SkyDrive 应用程序中选取一张照片。我进行去除红眼操作,并且照片编辑应用程序保存了我所做的更改。通过缓存文件更新程序合约,这些更改将自动发送回 SkyDrive。事实上,只要文件仍然存在,我后续所做的任何更改都将继续发送到 SkyDrive。我无须手动导出更改或将更改上载到 SkyDrive,缓存文件更新程序合约使 SkyDrive 上的文件就像存储在我本地 PC 上的文件一样,我始终可以拥有最新版本并可以随时更新。

此合约特别适用于作为用户经常用于保存和访问文件的主存储位置的应用程序。大多数应用程序并不需要使用缓存文件更新程序合约。此合约要求大量的状态管理、复杂数据流处理、互相冲突的解决方案和 UI 工作来确保它能充分发挥作用。如果对合约进行评级,那么此合约应该属于高级合约。

集成此合约后,每次您所维护的文件需要刷新或更新时都会激活您的应用程序(可能并不会向用户显示)。您的应用程序随时都可以由于此目的而激活,但所有应用程序激活操作都由系统驱动,而非由用户直接驱动。例如,如果用户向您的应用程序所维护的某个文件中保存数据,系统将激活您的应用程序以使您能够妥善处理(例如将更改上载到您的云服务)。

实施合约

开始实施缓存文件更新程序合约时,您可以遵循快速入门的说明。您的应用程序实施此合约后,将会自动激活以处理您所维护的文件中的变更。

您需要让系统了解您维护的是哪些 StorageFile。使用 setUpdateInformation 方法,您可以设置读/写权限,并控制如何以及何时可以激活应用程序以维护文件。一般来说,最好针对用户使用文件打开选取器合约从您的应用程序中选取,或使用文件保存选取器合约保存到您的应用程序中的每个文件都设置此信息。在我们的文件选取器合约 SDK 样本中,您可以找到支持缓存文件更新程序合约的 C#、C++ 和 JavaScript 代码。

此外,当实施缓存文件更新程序合约时,您可能需要提示用户提供凭据或处理版本冲突,然后您才能维护文件。在此类情况下,您可以让系统知道需要 UI,并且您的应用程序将在文件选取器中启动。

skydrive_creds

SkyDrive 应用程序在缓存文件更新程序操作过程中要求凭据

除了您的应用程序设置的选项外,要求更新或保存文件的应用程序可以控制部分缓存文件更新程序合约工作流。具体来说,在某些情况下,进行调用的应用程序可能会阻止您的应用程序显示 UI。此选择不会在您的应用程序中出现提示,如果进行调用的应用程序需要刷新或保存文件,而您的应用程序需要显示 UI 才能完成请求,调用将直接失败。

在整个过程中,您可以使用 UIStatus 枚举来了解您正在处理哪个步骤。

打造刷新和保存用户体验

尽管缓存文件更新程序合约的 UI 部分受到了限制,请确保您的应用程序遵循指南

  • 显示 UI: 仅当必须要求用户进行干预(凭据、文件冲突等)时请求 UI。向进行调用的应用程序返回失败情况,以让用户知道刷新或保存操作不成功。此外,如有必要,仅在您的主应用程序下次启动时显示提示消息(例如“文件已成功保存”),不要在文件选取器 UI 或其他 UI 表面(如 Toast)中显示。
  • 状态: 如果您的应用程序处理大量刷新和保存操作,请考虑在您的主应用程序的 UI 中显示每个任务的进度。这样用户便可以跟踪进度和解决问题。

端到端的工作流

综合来看,下面是端到端的缓存文件更新程序工作流概览。与前面的图类似,实施文件选取器合约的应用程序(如 SkyDrive)标记为“提供应用程序”。

端到端的缓存文件更新程序

结束语

在本篇博文中,我为您介绍了文件选取器合约,并向您展示了如何使用这些合约来帮助您的应用程序在 Windows 8 中打造全新的用户体验。文件打开选取器合约提供了一个很好的起点,使用户可以在其他 Windows 8 应用程序中使用他们在您的应用程序中存储、创建和管理的文件。随着您的应用程序提供更多高级功能,文件保存选取器和缓存文件更新程序合约可以进一步为您提供助力,使您的应用程序可以在更多 Windows 8 应用场景中发挥作用。

下面是一些需要注意的要点:

  • 文件选取器合约之间具有递进关系。从文件打开选取器合约入手,然后根据需要,进一步使用文件保存选取器合约,然后是缓存文件更新程序合约。
  • 让您的应用程序的个性化风格大放异彩!用户会比较熟悉使用您的应用程序的正常版本,因此,请确保将其中的个性化风格、外观以及导航功能延续到文件选取器中托管的版本里来。
  • 遵循 UX 指南,让您的应用程序在保留独特的个性化风格的同时,还可以使用文件选取器提供的所有功能。这样,用户在文件选取器中使用您的应用程序时,就能够获得一致的绝佳体验。

要了解 Windows 8 中文件选取器合约的详细信息,您可以参考以下链接,或在我们的论坛中提问。

链接

类型

要点

文件选取器合约指南和清单

UX 指南

文件选取器合约实施指南

快速入门:与文件选取器合约集成

快速入门

说明如何将文件选取器合约集成到您的应用程序中

Windows.Storage.Pickers.Provider

API 参考

文件打开选取器和文件保存选取器合约的相关参考文档

Windows.Storage.Provider 命名空间

API 参考

缓存文件更新程序合约的相关参考文档

文件选取器合约

代码样本

演示文件打开选取器、文件保存选取器和缓存文件更新程序合约的使用

谢谢!

--Windows 用户体验高级项目经理 Scott Hoogerwerf

投稿者:Derek Gebhard