使文件选取器异步-Windows Phone 8.1
本文关键字:Phone -Windows 异步 文件 选取 | 更新日期: 2023-09-27 18:21:35
我试图使用TaskComplectionSource
使文件打开选择器异步,但有时我会用-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在调试时几乎不会重现。有人知道这可能是什么原因吗?
不要这样做(不要试图将连续行为转换为异步)。为什么?
通常,当你的应用程序被放在后台时(例如,当你调用文件选择器时),它会被挂起,这里有一个小陷阱-当你连接了调试器时,你的应用将在不挂起的情况下工作。这肯定会引起一些麻烦。
还要注意的是,当你正常运行应用程序并启动选择器时,在某些情况下,你的应用程序可能会被终止(资源不足,用户将其关闭…)。因此,你需要VS添加的两件事作为模板:ContinuationManager和SuspendionManager。更多信息,请访问MSDN。在同一个链接,你会发现一个很好的程序来调试你的应用程序:
按照以下步骤测试调用AndContinue方法后应用程序终止的情况。这些步骤可确保调试器在完成操作并继续之后重新连接到您的应用程序。
在Visual Studio中,右键单击项目并选择"属性"。
在项目设计器中,在"启动"操作下的"调试"选项卡上,启用"不启动,但在代码启动时调试"。
运行您的应用程序并进行调试。这会部署应用程序,但不会运行它。
手动启动您的应用程序。调试器连接到应用程序。如果代码中有断点,则调试器会在断点处停止。当应用程序调用AndContinue方法时,调试器将继续运行。
如果你的应用程序调用文件选择器,请等待打开文件提供程序(例如,手机、照片或OneDrive)。如果您的应用程序呼叫在线身份验证提供商,请等待身份验证页面打开。
在"调试位置"工具栏上的"进程"下拉列表中,选择应用程序的进程。在Lifecycle Events(生命周期事件)下拉列表中,选择Suspend and Shutdown(挂起和关闭)以终止应用程序,但保持模拟器运行。
AndContinue操作完成后,调试器会在应用程序继续运行时自动重新附加到应用程序。
我已经将文件选择器更改为@Romasz提供的标准方式,它仍然崩溃。我已经调试了几个小时,我得到了相同的COMException
,但有时会提供信息:
"GetNavigationState doesn't support serialization of a parameter type which was passed to Frame.Navigate"
TaskCompletionSource
的代码似乎是有效的,这并没有错。我在Frame
的msdn文档中发现
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应该不允许这样的导航并抛出异常,但事实并非如此。。
编辑:另一个错误-如果你绑定了taped(比方说按钮taped)或类似的事件来命令启动FileOpenPicker
,你需要检查picker.PickFile..
之前是否被调用过-否则,当你快速点击该按钮时,你会得到一些对picker.PickFile..
和UnauthorizedAccessException
的调用。