我尝试使用TaskComplectionSource
使File open picker异步,但有时候我的应用程序以-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();
}
}
}
奇怪的是 - 调试时很难再现这个错误。有谁知道这可能是什么原因?
答案 0 :(得分:4)
不要这样做(不要试图将 Continuation 行为转换为 async )。为什么呢?
通常当你的应用程序被置于后台时(例如当你调用文件选择器时),它被暂停,这是一个小的陷阱 - 当你连接了调试器时,你的应用程序将工作而不会被暂停。当然这可能会带来一些麻烦。
另请注意,当您正常运行应用并触发选择器时,在某些情况下您的应用可以终止(资源不足,用户关闭它......)。因此,您需要在VS中添加两个作为模板的内容: ContinuationManager 和 SuspensionManager 。您可以在MSDN找到更多内容。在同一个链接中,您将找到一个调试应用程序的好程序:
按照以下步骤测试在调用AndContinue方法后终止应用程序的情况。这些步骤确保调试器在完成操作并继续后重新连接到您的应用程序。
在Visual Studio中,右键单击项目并选择“属性”。
在Project Designer中,在“开始”操作下的“调试”选项卡上,启用“不启动”,但在启动时调试我的代码。
使用调试运行您的应用。这会部署应用程序,但不会运行它。
手动启动您的应用。调试器附加到应用程序。如果代码中有断点,则调试器会在断点处停止。当您的应用调用AndContinue方法时,调试器将继续运行。
如果您的应用程序调用文件选择器,请等到您打开文件提供程序(例如,电话,照片或OneDrive)。如果您的应用程序呼叫在线身份提供商,请等待身份验证页面打开。
在“调试位置”工具栏上的“流程”下拉列表中,选择应用的流程。在Lifecycle Events下拉列表中,选择Suspend and Shutdown以终止您的应用,但保持模拟器正常运行。
- 醇>
AndContinue操作完成后,当应用程序继续时,调试器会自动重新连接到您的应用程序。
答案 1 :(得分: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
将被抛出。