图解使用Win8Api进行Metro风格的程序开发七----BackgroundDownloader和BackgroundUploader
我们紧接着上篇,这篇将介绍如何使用Windows.Networking.BackgroundTransfer API
中的BackgroundDownloader下载文件和BackgroundUploader上传文件
-----------------------------------我是华丽的分割线-----------------------------------------
今天我们要用Windows.Networking.BackgroundTransfer API中的
BackgroundDownloader下载文件和BackgroundUploader上传文件
本篇将介绍如下两个方面:
a)使用BackgroundDownloader下载文件
b)使用BackgroundUploader上传文件
我们的创建的步骤如下:
1)为了组织文件方便,我们先建一个文件夹BackgroundTransfer
2)向文件夹中添加如下两个文件:
DownloadFile.xaml,UploadFile.xaml
创建方法请参照前一篇.
3)此时的解决方案结构如下:
4)向我们的DataSource添加导航所需要的信息
修改我们的SampleDataSource.cs文件中的SampleDataSource类中的代码,
代码如下:
public SampleDataSource() { #region Group1 var group1 = new SampleDataGroup("FilePicker", "Use Windows.Storage.Pickers API", "Access and save files using the file picker", "Assets/FilePicker.jpg", ""); group1.Items.Add(new SampleDataItem("FilePicker-PickASinglePhoto", "Pick a single photo", "only one file can selected,file type is jpg,jpeg,png", "Assets/FilePicker.jpg", "only one file can selected ", "", group1, typeof(PickASinglePhoto))); group1.Items.Add(new SampleDataItem("FilePicker-PickMultipleFiles", "Pick multiple files", "you can pick multiple files", "Assets/FilePicker.jpg", "pick multiple files", "", group1, typeof(PickMultipleFiles))); group1.Items.Add(new SampleDataItem("FilePicker-PickAFolder", "Pick a folder", "you can pick a folder", "Assets/FilePicker.jpg", "Pick a folder", "", group1, typeof(PickAFolder))); group1.Items.Add(new SampleDataItem("FilePicker-SaveAFile", "Save a file", "you can save a file", "Assets/FilePicker.jpg", "Save a file", "", group1, typeof(SaveAFile))); this.AllGroups.Add(group1); #endregion #region Group2 var group2 = new SampleDataGroup("FileAceess", "Using Windows.Storage API", "File access", "Assets/FileAccess.jpg", ""); group2.Items.Add(new SampleDataItem("FileAceess-CreatingAFile", "Create a file", "Using CreateFileAsync Create a file", "Assets/FileAccess.jpg", "Using CreateFileAsync", "", group2, typeof(CreatingAFile))); group2.Items.Add(new SampleDataItem("FileAceess-WritingAndReadingText", "Write And Read A Text", "Using WriteTextAsync,ReadTextAsync Write And Read Text", "Assets/FileAccess.jpg", "Using WriteTextAsync,ReadTextAsync", "", group2, typeof(WritingAndReadingText))); group2.Items.Add(new SampleDataItem("FileAceess-WritingAndReadingBytes", "Writing and reading bytes in a file", "Using WriteBufferAsync,ReadBufferAsync Write And Read bytes", "Assets/FileAccess.jpg", "Using WriteBufferAsync,ReadBufferAsync", "", group2, typeof(WritingAndReadingBytes))); group2.Items.Add(new SampleDataItem("FileAceess-WritingAndReadingUsingStream", "Writing and reading using a stream", "Using OpenAsync Writing and reading using a stream", "Assets/FileAccess.jpg", "Using OpenAsync", "", group2, typeof(WritingAndReadingUsingStream))); group2.Items.Add(new SampleDataItem("FileAceess-DisplayingFileProperties", "Displaying file properties", "Using GetBasicPropertiesAsync Get File Properties", "Assets/FileAccess.jpg", "Using GetBasicPropertiesAsync", "", group2, typeof(DisplayingFileProperties))); group2.Items.Add(new SampleDataItem("FileAceess-PersistingAccess", "Persisting access to a storage item for future use", "Using MostRecentlyUsedList", "Assets/FileAccess.jpg", "Using MostRecentlyUsedList", "", group2, typeof(PersistingAccess))); group2.Items.Add(new SampleDataItem("FileAceess-CopyAFile", "Copy a file", "Using CopyAsync Copy a file", "Assets/FileAccess.jpg", "Using CopyAsync", "", group2, typeof(CopyAFile))); group2.Items.Add(new SampleDataItem("FileAceess-DeleteAFile", "Delete a file", "Using DeleteAsync Delete a file", "Assets/FileAccess.jpg", "Using DeleteAsync", "", group2, typeof(DeleteAFile))); this.AllGroups.Add(group2); #endregion #region Group3 var group3 = new SampleDataGroup("AccountPictureName", "Use Windows.System.UserProfile API", "Account Picture Name", "Assets/AccountPictureName.jpg", ""); group3.Items.Add(new SampleDataItem("AccountPictureName-GetUserDisplayName", "Get User DisplayName", "Use UserInformation.GetDisplayNameAsync Get User DisplayName", "Assets/AccountPictureName.jpg", "Use UserInformation.GetDisplayNameAsync", "", group3, typeof(GetUserDisplayName))); group3.Items.Add(new SampleDataItem("AccountPictureName-GetUserFirstLastName", "Get First Last Name", "Use UserInformation.GetFirstNameAsync,GetLastNameAsync Get First Name", "Assets/AccountPictureName.jpg", "Use UserInformation.GetFirstNameAsync ", "", group3, typeof(GetUserFirstLastName))); group3.Items.Add(new SampleDataItem("AccountPictureName-GetAccountPicture", "Get Account Picture", "Use UserInformation.GetAccountPicture Get Account Picture", "Assets/AccountPictureName.jpg", "Use UserInformation.GetAccountPicture", "", group3, typeof(GetAccountPicture))); group3.Items.Add(new SampleDataItem("AccountPictureName-SetAccountPictureAndListen", "Set AccountPicture And Listen", "Use UserInformation.SetAccountPicturesAsync Set AccountPicture", "Assets/AccountPictureName.jpg", "Use UserInformation.SetAccountPicturesAsync", "", group3, typeof(SetAccountPictureAndListen))); this.AllGroups.Add(group3); #endregion #region Group4 var group4 = new SampleDataGroup("ApplicationSettings", "ApplicationSettings", " Use the Windows.UI.ApplicationSettings namespace and WinJS.UI.SettingsFlyout", "Assets/ApplicationSettings.jpg", ""); group4.Items.Add(new SampleDataItem("ApplicationSettings-Default", "Default behavior with no settings integration", "Default behavior ", "Assets/ApplicationSettings.jpg", "Default behavior with no settings integration", "", group4, typeof(Default))); group4.Items.Add(new SampleDataItem("ApplicationSettings-AddSettings", "Add settings commands to the settings charm", "Add settings", "Assets/ApplicationSettings.jpg", "Add settings commands to the settings charm ", "", group4, typeof(AddSettings))); this.AllGroups.Add(group4); #endregion #region Group5 var Group5 = new SampleDataGroup("AssociationLaunching", "Use Windows.System.Launcher API", "Association Launching", "Assets/AssociationLaunching.jpg", ""); Group5.Items.Add(new SampleDataItem("AssociationLaunching-LaunchFile", "Launching a file", "Use Windows.System.Launcher.LaunchFileAsync", "Assets/AssociationLaunching.jpg", "Use Windows.System.Launcher.LaunchFileAsync", "", Group5, typeof(LaunchFile))); Group5.Items.Add(new SampleDataItem("AssociationLaunching-LaunchUri", "Launching a URI", "Use Windows.System.Launcher.LaunchUriAsync", "Assets/AssociationLaunching.jpg", "Use Windows.System.Launcher.LaunchUriAsync", "", Group5, typeof(LaunchUri))); Group5.Items.Add(new SampleDataItem("AssociationLaunching-ReceiveFile", "Receiving a file", "Receiving a file", "Assets/AssociationLaunching.jpg", "Receiving a file", "", Group5, typeof(ReceiveFile))); Group5.Items.Add(new SampleDataItem("AssociationLaunching-ReceiveUri", "Receiving a URI", "Receiving a URI", "Assets/AssociationLaunching.jpg", "Receiving a URI", "", Group5, typeof(ReceiveUri))); this.AllGroups.Add(Group5); #endregion #region Group6 var Group6 = new SampleDataGroup("BackgroundTransfer", "Use Windows.Networking.BackgroundTransfer API", "BackgroundDownloader And BackgroundUploader", "Assets/BackgroundTransfer.jpg", ""); Group6.Items.Add(new SampleDataItem("BackgroundTransfer-DownloadFile", "Download Files", "Use BackgroundDownloader", "Assets/BackgroundTransfer.jpg", "BackgroundDownloader", "", Group6, typeof(DownloadFile))); Group6.Items.Add(new SampleDataItem("BackgroundTransfer-UploadFile", "Upload Files", "Use BackgroundUploader", "Assets/BackgroundTransfer.jpg", "BackgroundUploader", "", Group6, typeof(UploadFile))); this.AllGroups.Add(Group6); #endregion }
5)我们的导航这样就做好了,效果图:
点击 BackgroundTransfer
6)使用BackgroundDownloader下载文件
我们使用BackgroundDownloader来下载文件,使用CancellationTokenSource来取消下载,
使用Pause方法来暂停下载,使用Resume来接着上次继续下载,使用Progress来显示进度。
修改DownloadFile.xaml的xaml:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel> <TextBlock TextWrapping="Wrap" Style="{StaticResource SubheaderTextStyle}" Text="When downloading a file from a server, application developers must ensure they receive user consent for the download. Additionally they must expose facilities to control each download (pause, resume, and cancel) and ensure progress visibility when the application is in the foreground. The Background Transfer API enables users to transfer content in the background. Therefore, application developers must also ensure they handle application suspension/resumption and termination/activation cases as well."/> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <TextBlock Text="Remote address: " Style="{StaticResource BodyTextStyle}" Margin="0,8,10,0"/> <TextBox x:Name="serverAddressField" Text="http://images.cnblogs.com/cnblogs_com/refactor/387664/t_logo.jpg" Width="500" /> </StackPanel> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <TextBlock Text="Local file name: " Style="{StaticResource BodyTextStyle}" Margin="0,8,17,0" /> <TextBox x:Name="fileNameField" Text="Refactor.jpg" Width="500"/> </StackPanel> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <Button x:Name="StartDownloadButton" Content="Start Download" Margin="0,0,10,0" Click="StartDownload_Click"/> <Button x:Name="PauseAllButton" Content="Pause All" Margin="0,0,10,0" Click="PauseAll_Click"/> <Button x:Name="ResumeAllButton" Content="Resume All" Margin="0,0,10,0" Click="ResumeAll_Click"/> <Button x:Name="CancelAllButton" Content="Cancel All" Margin="0,0,10,0" Click="CancelAll_Click"/> </StackPanel> </StackPanel> <Grid x:Name="Output" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1"> <TextBlock x:Name="OutputTextBlock" Style="{StaticResource SubheaderTextStyle}" TextWrapping="Wrap"/> </Grid> </Grid>
修改后台代码:
public sealed partial class DownloadFile : Page { /// <summary> /// 异步下载操作列表 /// </summary> private List<DownloadOperation> activeDownloads; /// <summary> /// 告知应被取消 /// </summary> private CancellationTokenSource cts; public DownloadFile() { this.InitializeComponent(); activeDownloads = new List<DownloadOperation>(); cts = new CancellationTokenSource(); } /// <summary> /// Invoked when this page is about to be displayed in a Frame. /// </summary> /// <param name="e">Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page.</param> protected override void OnNavigatedTo(NavigationEventArgs e) { } private async void StartDownload_Click(object sender, RoutedEventArgs e) { try { Uri source = new Uri(serverAddressField.Text.Trim()); string destination = fileNameField.Text.Trim(); if (destination == "") { Log("A local file name is required."); return; } //先在图片库创建一个文件,默认创建Refactor.jpg StorageFile destinationFile = await KnownFolders.PicturesLibrary.CreateFileAsync( destination, CreationCollisionOption.GenerateUniqueName); BackgroundDownloader downloader = new BackgroundDownloader(); //创建下载 DownloadOperation download = downloader.CreateDownload(source, destinationFile); Log(String.Format("Downloading {0} to {1}, {2}", source.AbsoluteUri, destinationFile.Name, download.Guid)); // 添加进度和完成处理程序 await HandleDownloadAsync(download, true); } catch (Exception ex) { Log("Download Error"+ ex.Message); } } private void PauseAll_Click(object sender, RoutedEventArgs e) { try { Log("Downloads: " + activeDownloads.Count); foreach (DownloadOperation download in activeDownloads) { if (download.Progress.Status == BackgroundTransferStatus.Running) { download.Pause(); Log("Paused: " + download.Guid); } else { Log(String.Format("Skipped: {0}, Status: {1}", download.Guid, download.Progress.Status)); } } } catch (Exception ex) { Log("Pause error"+ex.Message); } } private void ResumeAll_Click(object sender, RoutedEventArgs e) { try { Log("Downloads: " + activeDownloads.Count); foreach (DownloadOperation download in activeDownloads) { if (download.Progress.Status == BackgroundTransferStatus.PausedByApplication) { download.Resume(); Log("Resumed: " + download.Guid); } else { Log(String.Format("Skipped: {0}, Status: {1}", download.Guid, download.Progress.Status)); } } } catch (Exception ex) { Log("Resume error"+ex.Message); } } private void CancelAll_Click(object sender, RoutedEventArgs e) { Log("Canceling Downloads: " + activeDownloads.Count); cts.Cancel(); cts.Dispose(); // Re-create the CancellationTokenSource and activeDownloads for future downloads. cts = new CancellationTokenSource(); activeDownloads = new List<DownloadOperation>(); } private async Task HandleDownloadAsync(DownloadOperation download, bool start) { try { //在下载列表中添加,以便可以 暂停和开始 activeDownloads.Add(download); //声明进度 Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress); if (start) { //开始下载并添加进度回调 await download.StartAsync().AsTask(cts.Token, progressCallback); } else { await download.AttachAsync().AsTask(cts.Token, progressCallback); } //获取服务器响应信息 ResponseInformation response = download.GetResponseInformation(); Log(String.Format("Completed: {0}, Status Code: {1}", download.Guid, response.StatusCode)); } catch (TaskCanceledException) { Log("Download cancelled."); } catch (Exception ex) { Log("Error" + ex.Message); } finally { activeDownloads.Remove(download); } } //注意此事件是由后台触发,不能在UI直接访问 private void DownloadProgress(DownloadOperation download) { MarshalLog(String.Format("Progress: {0}, Status: {1}", download.Guid, download.Progress.Status)); double percent = 100; if (download.Progress.TotalBytesToReceive > 0) { percent = download.Progress.BytesReceived * 100 / download.Progress.TotalBytesToReceive; } MarshalLog(String.Format(" - Transfered bytes: {0} of {1}, {2}%", download.Progress.BytesReceived, download.Progress.TotalBytesToReceive, percent)); if (download.Progress.HasRestarted) { MarshalLog(" - Download restarted"); } if (download.Progress.HasResponseChanged) { // We've received new response headers from the server. MarshalLog(" - Response updated; Header count: " + download.GetResponseInformation().Headers.Count); // If you want to stream the response data this is a good time to start. // download.GetResultStreamAt(0); } } private void MarshalLog(string value) { var ignore = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { Log(value); }); } private void Log(string message) { OutputTextBlock.Text += message + "\r\n"; } }
修改Package.appxmanifest:
效果图:
点击 Start Download
在图片库中:
7)使用BackgroundUploader上传文件
我们使用BackgroundDownloader来下载文件,使用CancellationTokenSource来取消下载,
使用Pause方法来暂停下载,使用Resume来接着上次继续下载,使用Progress来显示进度。
修改UploadFile.xaml的xaml:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel> <TextBlock TextWrapping="Wrap" Style="{StaticResource SubheaderTextStyle}" Text="When uploading a file to a server, application developers must ensure they receive user consent for the upload. Additionally they must expose facilities to control each upload (like cancel) and ensure progress visibility when the application is in the foreground. The Background Transfer API enables users to transfer content in the background. Therefore, application developers must also ensure they handle application suspension/resumption and termination/activation cases as well."/> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <TextBlock Text="Remote address: " Style="{StaticResource SubheaderTextStyle}" Margin="0,8,10,0"/> <TextBox x:Name="serverAddressField" Text="http://images.cnblogs.com/cnblogs_com/refactor/387664/" Width="400" /> </StackPanel> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <Button x:Name="StartUploadButton" Content="Start Upload" Margin="0,0,10,0" Click="StartUpload_Click"/> <Button x:Name="StartMultipartUploadButton" Content="Start Multipart Upload" Margin="0,0,10,0" Click="StartMultipartUpload_Click"/> <Button x:Name="CancelAllButton" Content="Cancel All" Margin="0,0,10,0" Click="CancelAll_Click"/> </StackPanel> </StackPanel> <Grid x:Name="Output" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1"> <TextBlock x:Name="OutputTextBlock" Style="{StaticResource SubheaderTextStyle}" TextWrapping="Wrap"/> </Grid> </Grid>
修改后台代码:
public sealed partial class UploadFile : Page { private CancellationTokenSource cts; public UploadFile() { this.InitializeComponent(); cts = new CancellationTokenSource(); } /// <summary> /// Invoked when this page is about to be displayed in a Frame. /// </summary> /// <param name="e">Event data that describes how this page was reached. The Parameter /// property is typically used to configure the page.</param> protected override void OnNavigatedTo(NavigationEventArgs e) { } private async void StartUpload_Click(object sender, RoutedEventArgs e) { try { Uri uri = new Uri(serverAddressField.Text.Trim()); FileOpenPicker picker = new FileOpenPicker(); picker.FileTypeFilter.Add("*"); StorageFile file = await picker.PickSingleFileAsync(); if (file == null) { Log("No file selected"); return; } BackgroundUploader uploader = new BackgroundUploader(); uploader.SetRequestHeader("Filename", file.Name); UploadOperation upload = uploader.CreateUpload(uri, file); Log(String.Format("Uploading {0} to {1}, {2}", file.Name, uri.AbsoluteUri, upload.Guid)); // Attach progress and completion handlers. await HandleUploadAsync(upload, true); } catch (Exception ex) { LogException("Upload Error", ex); } } private async void StartMultipartUpload_Click(object sender, RoutedEventArgs e) { try { Uri uri = new Uri(serverAddressField.Text.Trim()); FileOpenPicker picker = new FileOpenPicker(); picker.FileTypeFilter.Add("*"); IReadOnlyList<StorageFile> files = await picker.PickMultipleFilesAsync(); if (files.Count == 0) { Log("No file selected"); return; } List<BackgroundTransferContentPart> parts = new List<BackgroundTransferContentPart>(); for (int i = 0; i < files.Count; i++) { BackgroundTransferContentPart part = new BackgroundTransferContentPart("File" + i, files[i].Name); part.SetFile(files[i]); parts.Add(part); } BackgroundUploader uploader = new BackgroundUploader(); UploadOperation upload = await uploader.CreateUploadAsync(uri, parts); String fileNames = files[0].Name; for (int i = 1; i < files.Count; i++) { fileNames += ", " + files[i].Name; } Log(String.Format("Uploading {0} to {1}, {2}", fileNames, uri.AbsoluteUri, upload.Guid)); // Attach progress and completion handlers. await HandleUploadAsync(upload, true); } catch (Exception ex) { LogException("Multipart Upload Error", ex); } } private void CancelAll_Click(object sender, RoutedEventArgs e) { Log("Canceling all active uploads"); cts.Cancel(); cts.Dispose(); // Re-create the CancellationTokenSource and activeUploads for future uploads. cts = new CancellationTokenSource(); } // Note that this event is invoked on a background thread, so we cannot access the UI directly. private void UploadProgress(UploadOperation upload) { MarshalLog(String.Format("Progress: {0}, Status: {1}", upload.Guid, upload.Progress.Status)); double percent = 100; if (upload.Progress.TotalBytesToReceive > 0) { percent = upload.Progress.BytesReceived * 100 / upload.Progress.TotalBytesToReceive; } MarshalLog(String.Format(" - Transfered bytes: {0} of {1}, {2}%", upload.Progress.BytesReceived, upload.Progress.TotalBytesToReceive, percent)); if (upload.Progress.HasRestarted) { MarshalLog(" - Upload restarted"); } if (upload.Progress.HasResponseChanged) { // We've received new response headers from the server. MarshalLog(" - Response updated; Header count: " + upload.GetResponseInformation().Headers.Count); // If you want to stream the response data this is a good time to start. // upload.GetResultStreamAt(0); } } private async Task HandleUploadAsync(UploadOperation upload, bool start) { try { Progress<UploadOperation> progressCallback = new Progress<UploadOperation>(UploadProgress); if (start) { // Start the upload and attach a progress handler. await upload.StartAsync().AsTask(cts.Token, progressCallback); } else { // The upload was already running when the application started, re-attach the progress handler. await upload.AttachAsync().AsTask(cts.Token, progressCallback); } ResponseInformation response = upload.GetResponseInformation(); Log(String.Format("Completed: {0}, Status Code: {1}", upload.Guid, response.StatusCode)); } catch (TaskCanceledException) { Log("Upload cancelled."); } catch (Exception ex) { LogException("Error", ex); } } private void LogException(string title, Exception ex) { WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult); if (error == WebErrorStatus.Unknown) { Log(title + ": " + ex); } else { Log(title + ": " + error); } } // When operations happen on a background thread we have to marshal UI updates back to the UI thread. private void MarshalLog(string value) { var ignore = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { Log(value); }); } private void Log(string message) { OutputTextBlock.Text += message + "\r\n"; } }
未完待续,敬请期待...
转载请注明出处:http://www.cnblogs.com/refactor/