2014-09-10 28 views
1

我试着用TaskComplectionSource使文件打开选择器异步但是有时我让我的应用程序关闭与-1返回值,有时我得到的异常,如:制作文件选择异步 - 的Windows Phone 8.1

[System.Runtime.InteropServices.COMException] = {System.Runtime.InteropServices.COMException (0x80004005): Unspecified error 

Unspecified error 

    at Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAndContinue() 
    at PhotosGraphos.Mobile.Common.StorageFileExtensions.<PickSingleFileAsyncMobile.. 

代码:

public static class StorageFileExtensions 
{ 
    private static TaskCompletionSource<StorageFile> PickFileTaskCompletionSource; 

    private static bool isPickingFileInProgress; 
    public static async Task<StorageFile> PickSingleFileAsyncMobile(this FileOpenPicker openPicker) 
    { 
     if (isPickingFileInProgress) 
      return null; 

     isPickingFileInProgress = true; 
     PickFileTaskCompletionSource = new TaskCompletionSource<StorageFile>(); 

     var currentView = CoreApplication.GetCurrentView(); 
     currentView.Activated += OnActivated; 
     openPicker.PickSingleFileAndContinue(); 

     StorageFile pickedFile; 
     try 
     { 
      pickedFile = await PickFileTaskCompletionSource.Task; 
     } 
     catch (TaskCanceledException) 
     { 
      pickedFile = null; 
     } 
     finally 
     { 
      PickFileTaskCompletionSource = null; 
      isPickingFileInProgress = false; 
     } 

     return pickedFile; 
    } 

    private static void OnActivated(CoreApplicationView sender, IActivatedEventArgs args) 
    { 
     var continuationArgs = args as FileOpenPickerContinuationEventArgs; 
     sender.Activated -= OnActivated; 

     if (continuationArgs != null && continuationArgs.Files.Any()) 
     { 
      StorageFile pickedFile = continuationArgs.Files.First(); 
      PickFileTaskCompletionSource.SetResult(pickedFile); 
     } 
     else 
     { 
      PickFileTaskCompletionSource.SetCanceled(); 
     } 
    } 
} 

有什么奇怪的 - 这个bug在调试时很难再现。有没有人有任何想法可能是什么原因呢?

+1

对于初学者来说,您不应该在每次调用此方法时都使用静态任务完成源。它应该是本地的方法调用。 – Servy 2014-09-10 20:29:58

+0

你是对的 - 这显然是“代码味道”。然而,它没有什么问题,我已经提到过在我的问题中 - 它不用于此方法以外的任何地方,它不是多线程方法(picker不能从非ui线程启动),因此竞争条件不存在。 – fex 2014-09-10 20:36:47

回答

4

不要这样做(不要试图将延续行为变为异步)。为什么?

通常,当您的应用程序进入后台(例如,当您调用文件选取器时),它将被暂停,这里有一个小陷阱 - 当您有调试器连接时,您的应用程序将不会被暂停。当然,这可能会导致一些麻烦。

还请注意,当您正常运行您的应用程序并且您启动了一个选取器时,则在某些情况下,您的应用程序可能会被终止(低资源,用户关闭它...)。所以你需要在这里添加两件由VS作为模板添加的东西:ContinuationManagerSuspensionManager。更多你会发现在MSDN。在同一链接中,您将找到一个很好的程序来调试您的应用程序:

请按照以下步骤测试应用程序在调用AndContinue方法后终止的情况。这些步骤确保在完成操作并继续之后调试器重新连接到您的应用程序。

  1. 在Visual Studio中,右键单击您的项目并选择属性。

  2. 在Project Designer中,在启动操作下的调试选项卡上,启用不启动,但在启动时调试我的代码。

  3. 通过调试运行您的应用程序。这部署应用程序,但不运行它。

  4. 手动启动您的应用程序。调试器附加到应用程序。如果您的代码中有断点,则调试程序停在断点处。当您的应用程序调用AndContinue方法时,调试器将继续运行。

  5. 如果您的应用程序调用文件选取器,请等到您打开文件提供程序(例如,电话,照片或OneDrive)。如果您的应用程序调用在线身份提供程序,请等待身份验证页面打开。

  6. 在调试位置工具栏上的进程下拉列表中,为您的应用程序选择进程。在生命周期事件下拉列表中,选择挂起和关闭来终止您的应用程序,但保持模拟器运行。

  7. AndContinue操作完成后,调试器在应用程序继续时自动重新连接到您的应用程序。

+0

很好的答案,虽然已经知道ContinuationManager,但我认为它可以被简化。你知道什么时候应用程序被暂停时等待TaskCompletionSource发生了什么? – fex 2014-09-10 21:55:06

+0

@fex在大多数情况下,资源被保存在内存中:*操作系统尝试尽可能多地在内存中保留已暂停的应用程序* - 您可以在[MSDN](http://msdn.microsoft.com/zh-cn/我们/库/窗/应用/ XAML/hh464925.aspx)。我不确定程序是否会在*等待TCS *之后返回到该点* - 当然您可以测试它 - 在*生命周期事件下拉列表中选择挂起,然后选择继续 - 您可以测试发生了什么。 – Romasz 2014-09-11 06:30:05

1

我已经改变了文件选择通过@Romasz提供的标准的方式 - 它仍然是崩溃。我已经调试好几个小时,我也得到相同的COMException的,但是有时提供的信息:

"GetNavigationState doesn't support serialization of a parameter type which was passed to Frame.Navigate" 

这似乎与TaskCompletionSource作品的代码并没有什么不妥。我MSDN文档中发现了Frame

Note: The serialization format used by these methods is for internal use only. Your app should not form any dependencies on it. Additionally, this format supports serialization only for basic types like string, char, numeric and GUID types.

而我通过我的模型类对象在导航参数 - 因此它被保存在导航堆栈,因此它不能被序列化。这个教训是:不使用非基本类型的导航参数 - Frame.Navigate应该禁止这样的导航和抛出异常 - 但事实并非如此..

编辑: 另一个错误 - 如果绑定抽头(比方说按钮点击)或类似的事件来命令启动FileOpenPicker你需要检查picker.PickFile..之前是否被调用 - 否则当你点击该按钮时,你会很快拨打picker.PickFile..UnauthorizedAccessException将被抛出。

+1

+1 - 仅当您的应用在后台被OS终止时才会注意到这种情况(罕见情况,但可能会发生)。此外,我不会拨打*双击问题*一个错误,只是我们应该确保用户不会多次启动选取器。 – Romasz 2014-09-11 18:19:55