在 Windows Phone 8.1 中,增加了 FilePicker 的方式與文件打交道,最大的亮點在於這種方式不僅可以瀏覽手機上的文件,還可以瀏覽符合協議的應用里的文件!
比如點擊 OneDrive 就會打開 OneDrive 應用:

(1)FileOpenPicker
FileOpenPicker 也就是選擇文件,可以設置打開單選界面或多選界面。
1)實例化 FileOpenPicker 對象,並設置 ContinuationData
private void openFileButton_Click(object sender, RoutedEventArgs e) { FileOpenPicker imageOpenPicker = new FileOpenPicker(); imageOpenPicker.FileTypeFilter.Add(".jpg"); imageOpenPicker.FileTypeFilter.Add(".png");
imageOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; imageOpenPicker.ContinuationData["Operate"] = "OpenImage"; imageOpenPicker.PickSingleFileAndContinue(); }
FileOpenPicker 可以設置 FileTypeFilter,方便文件的瀏覽;還可以設置選擇界面的開始目錄(SuggestedStartLocation)。
因為在打開選擇文件的界面后當前應用會掛起,所以需要 ContinuationData 來記錄一些信息,以保證當應用恢復時能夠保持之前的信息。
2)重寫 App.xaml.cs 的 OnActivated 方法
當用戶選擇了文件之后會返回到之前的應用,這時需要重寫 OnActivated 方法讓應用跳轉到指定頁面,並傳遞用戶選擇的文件。
protected override void OnActivated(IActivatedEventArgs args) { if( args is FileOpenPickerContinuationEventArgs ) { Frame rootFrame = Window.Current.Content as Frame; if( rootFrame == null ) { rootFrame = new Frame(); rootFrame.CacheSize = 1; Window.Current.Content = rootFrame; } if( rootFrame.Content == null ) { if( rootFrame.ContentTransitions != null ) { this.transitions = new TransitionCollection(); foreach( var c in rootFrame.ContentTransitions ) { this.transitions.Add(c); } } rootFrame.ContentTransitions = null; rootFrame.Navigated += this.RootFrame_FirstNavigated; if( !rootFrame.Navigate(typeof(MainPage)) ) { throw new Exception("Failed to create first page"); } } if( !rootFrame.Navigate(typeof(MainPage)) ) { throw new Exception("Failed to create target page"); } MainPage targetPage = rootFrame.Content as MainPage; targetPage.FilePickerEventArgs = (FileOpenPickerContinuationEventArgs)args; Window.Current.Activate(); } }
首先是要判斷之前的行為是不是 FileOpenPicker 引起的,然后獲取 Frame 並跳轉到指定頁面,將包含用戶選擇文件的信息 args 傳遞到指定頁面中。
3)添加 FileOpenPickerContinuationEventArgs 屬性和 ContinuFileOpenPicker 方法
當應用將 args 傳遞到頁面去后,剩下的就是處理文件了:
private FileOpenPickerContinuationEventArgs filePickerEventArgs; public FileOpenPickerContinuationEventArgs FilePickerEventArgs { get { return filePickerEventArgs; } set { filePickerEventArgs = value; ContinuFileOpenPicker(filePickerEventArgs); } } private async void ContinuFileOpenPicker(FileOpenPickerContinuationEventArgs args) { if( args.ContinuationData["Operate"] as string == "OpenImage" && args.Files != null && args.Files.Count > 0 ) { StorageFile file = args.Files[0]; BitmapImage image = new BitmapImage(); await image.SetSourceAsync(await file.OpenAsync(FileAccessMode.Read)); myImage.Source = image; } }
(2)AccessCache
AccessCache 也就是指對用戶選擇文件或文件夾的緩存,包括 MostRecentlyUsedList 和 FutureAccessList。
MostRecentlyUsedList 可以保存 25 項,並會根據用戶使用情況自動排序,當新的進來后超過 25 項了則會自動將最舊的刪除。
FutureAccessList 則可以保存 1000 項,但不會自動排序,需要開發者自行管理。
保存方法:
private async void ContinuFileOpenPicker(FileOpenPickerContinuationEventArgs args) { if( args.ContinuationData["Image"] as string == "OpenImage" && args.Files != null && args.Files.Count > 0 ) { StorageFile file = args.Files[0]; BitmapImage image = new BitmapImage(); await image.SetSourceAsync(await file.OpenAsync(FileAccessMode.Read)); myImage.Source = image; StorageApplicationPermissions.MostRecentlyUsedList.Add(file, "20140528"); StorageApplicationPermissions.FutureAccessList.Add(file, "20140528"); } }
讀取方法:
private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e) { var mruList = StorageApplicationPermissions.MostRecentlyUsedList.Entries; foreach( var item in mruList ) { StorageFile file = await StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(item.Token); BitmapImage image = new BitmapImage(); await image.SetSourceAsync(await file.OpenAsync(FileAccessMode.Read)); Image img = new Image(); img.Source = image; img.Stretch = Stretch.Uniform; img.Margin = new Thickness(0, 0, 0, 10); imagesStackPanel.Children.Add(img); } }
開發者可以靈活使用這兩個列表,方便用戶瀏覽最近使用過的文件。
(3)FileSavePicker
既然有 OpenPicker,自然就有 SavePicker。
FileSavePicker 的使用方法與 FileOpenPicker 非常相似。
1)實例化 FileSavePicker 對象,並設置 ContinuationData
private void saveButton_Click(object sender, RoutedEventArgs e) { FileSavePicker imageSavePicker = new FileSavePicker(); imageSavePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; imageSavePicker.SuggestedFileName = "Test"; imageSavePicker.FileTypeChoices.Add("Txt", new List<string>() { ".txt" }); imageSavePicker.ContinuationData["Txt"] = "SaveTxt"; imageSavePicker.PickSaveFileAndContinue(); }
實例化 FileSavePicker 對象后,設置 FileName 和 FileType。
當用戶選擇了某個文件夾后,系統就會在該文件夾中新建一個該 FileName 和 FileType 的文件,並將該文件放到 FileSavePickerContinuationEventArgs 中。
2)重寫 App.xaml.cs 的 OnActivated 方法
與 FileOpenPicker 一樣,同樣需要重寫 OnActivated 方法,這次要檢查的 args 類型為 FileSavePickerContinuationEventArgs:
protected override void OnActivated(IActivatedEventArgs args) { if( args is FileSavePickerContinuationEventArgs ) { Frame rootFrame = Window.Current.Content as Frame; // 不要在窗口已包含內容時重復應用程序初始化, // 只需確保窗口處於活動狀態 if( rootFrame == null ) { // 創建要充當導航上下文的框架,並導航到第一頁 rootFrame = new Frame(); // TODO: 將此值更改為適合您的應用程序的緩存大小 rootFrame.CacheSize = 1; if( args.PreviousExecutionState == ApplicationExecutionState.Terminated ) { // TODO: 從之前掛起的應用程序加載狀態 } // 將框架放在當前窗口中 Window.Current.Content = rootFrame; } if( rootFrame.Content == null ) { // 刪除用於啟動的旋轉門導航。 if( rootFrame.ContentTransitions != null ) { this.transitions = new TransitionCollection(); foreach( var c in rootFrame.ContentTransitions ) { this.transitions.Add(c); } } rootFrame.ContentTransitions = null; rootFrame.Navigated += this.RootFrame_FirstNavigated; // 當導航堆棧尚未還原時,導航到第一頁, // 並通過將所需信息作為導航參數傳入來配置 // 新頁面 if( !rootFrame.Navigate(typeof(MainPage)) ) { throw new Exception("Failed to create initial page"); } } if( !rootFrame.Navigate(typeof(MainPage)) ) { throw new Exception("Failed to create target page"); } MainPage targetPage = rootFrame.Content as MainPage; targetPage.SavePickerArgs = (FileSavePickerContinuationEventArgs)args; // 確保當前窗口處於活動狀態 Window.Current.Activate(); } }
3)添加 FileSavePickerContinuationEventArgs 屬性和 ContinuFileSavePicker 方法
最后在 ContinuFileSavePicker 方法中對要保存的文件進行操作:
private FileSavePickerContinuationEventArgs savePickerArgs; public FileSavePickerContinuationEventArgs SavePickerArgs { get { return savePickerArgs; } set { savePickerArgs = value; ContinuFileSavePicker(savePickerArgs); } } private async void ContinuFileSavePicker(FileSavePickerContinuationEventArgs args) { if( args.ContinuationData["Txt"] as string == "SaveTxt" && args.File != null ) { StorageFile txt = args.File; await FileIO.WriteTextAsync(txt, "1224677"); } }
