前面【UWP开发之Mvvmlight实践五:SuspensionManager中断挂起以及复原处理】章节已经提到过Template10,为了认识MvvmLight的区别特做了此实例。
原代码地址:https://github.com/NewBLife/UWP/tree/master/MvvmDemo/FileOperationDemo
应用主要功能:
-
本地任何文件多项选择添加
-
照相机图片添加
-
显示添加文件(.jpg.png.pdf.xls等)的缩略图
-
列表文件删除
-
默认程序显示添加后的文件
应用技术点:
-
汉堡菜单(随窗口大小自动收缩)
-
系统返回按钮操作
-
StorageFile挂起复原
-
文件访问权限
应用截图如下:
====PC端====
主界面
点击【+】添加文件
点击列表任何文件(例如:0.PNG),使用默认应用打开文件
点击【头像】拍照
点击【Delete】可以删除列表文件
点击【设定】打开设定页面
====手机端====
主界面
点击【+】添加文件
选择任何文件(例如:list.pdf),使用默认应用打开文件
点击【头像】拍照
点击汉堡菜单选择【设定】
技术详解:
1.StorageFile文件的挂起复原
应用以外文件夹的文件挂起复原时如果通过路径获取StorageFile对象会出现以下异常,一般是通过令牌来做处理。
“System.UnauthorizedAccessException”类型的异常在 FileOperationDemo.exe 中发生,但未在用户代码中进行处理 其他信息: 拒绝访问。 (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
第一步:添加时从MRU中获取文件访问令牌
#region 获取 MRU 中文件的令牌 // 详细: https://msdn.microsoft.com/zh-cn/library/windows/apps/hh972603 // 应用外部文件访问时使用 _FileMruToken = StorageApplicationPermissions.FutureAccessList.Add(file); #endregion
第二步:应用挂起时只保存令牌数据StorageFile属性JsonIgnore标记添加(StorageFile等对象无法反序列化复原)
/// <summary> /// 文件信息 /// </summary> [JsonIgnore] public StorageFile File { get { return _File; } set { Set(ref _File, value); } } /// <summary> /// 文件访问令牌 /// 挂起复原时使用 /// </summary> [JsonProperty] public string FileMruToken { get { return _FileMruToken; } set { _FileMruToken = value; } }
第三步:复原时使用令牌获取StorageFile对象
// 应用外部文件 return await StorageApplicationPermissions.FutureAccessList.GetFileAsync(_FileMruToken);
2.默认应用打开文件时权限取得
// 默认应用打开文件 await Windows.System.Launcher.LaunchFileAsync(file);
直接赋值StorageFile对象到file时,是无法打开文件的,因为没有权限。这时也需要令牌从StorageApplicationPermissions.FutureAccessList获取StorageFile对象才能打开。
// 应用外部文件 return await StorageApplicationPermissions.FutureAccessList.GetFileAsync(_FileMruToken);
3.系统返回按钮事件注销时机
由于不想应用最后返回按下时关闭特加入此功能
/// <summary> /// 返回按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OnBackRequested(object sender, BackRequestedEventArgs e) { e.Handled = true; NavigationService.GoBack(); }
在OnNavigatedToAsync注册事件
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState) { try { if (suspensionState.Any()) { FileList = SerializationService.Json.Deserialize<ObservableCollection<FileInfo>>(suspensionState[nameof(FileList)]?.ToString()); } // 注册系统返回按钮事件 SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested; await Task.CompletedTask; } catch (Exception ex) { Debug.WriteLine(ex.Message); Debug.WriteLine(ex.Source); Debug.WriteLine(ex.StackTrace); } }
在OnNavigatingFromAsync注销事件
public override async Task OnNavigatingFromAsync(NavigatingEventArgs args) { args.Cancel = false; // 注销系统返回按钮事件 SystemNavigationManager.GetForCurrentView().BackRequested -= OnBackRequested; await Task.CompletedTask; }