前面【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; }