Windows 8 Store Apps学习(66) 后台任务: 下载和上传2014-09-02 cnblogs webabcd介绍重新想象 Windows 8 Store Apps 之 后台任务后台下载任务后台上传任务示例扩展了 DownloadOperation 和 UploadOperation,以便下载进度或上传进度可通知BackgroundTask/TransferModel.cs
/* * 扩展了 DownloadOperation 和 UploadOperation,以便下载进度或上传进度可通知 */using System;using System.ComponentModel;using Windows.Networking.BackgroundTransfer;namespace XamlDemo.BackgroundTask{public class TransferModel : INotifyPropertyChanged{public DownloadOperation DownloadOperation { get; set; }public UploadOperation UploadOperation { get; set; }public string Source { get; set; }public string Destination { get; set; }private string _progress;public string Progress{get { return _progress; }set{_progress = value;RaisePropertyChanged("Progress");}}public event PropertyChangedEventHandler PropertyChanged;protected void RaisePropertyChanged(string name){if (PropertyChanged != null){PropertyChanged(this, new PropertyChangedEventArgs(name));}}}}
1、演示后台下载任务的应用BackgroundTask/TransferDownload.xaml
<Pagex:Class="XamlDemo.BackgroundTask.TransferDownload"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:XamlDemo.BackgroundTask"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="Transparent"><StackPanel Margin="120 0 0 0"><ScrollViewer Height="100"><TextBlock Name="lblMsg" FontSize="14.667" TextWrapping="Wrap"/></ScrollViewer><Button Name="btnAddDownload" Content="新增一个下载任务" Margin="0 10 0 0" Click="btnAddDownload_Click"/><Button Name="btnPause" Content="暂停所有下载任务" Margin="0 10 0 0" Click="btnPause_Click"/><Button Name="btnResume" Content="继续所有下载任务" Margin="0 10 0 0" Click="btnResume_Click"/><Button Name="btnCancel" Content="取消所有下载任务" Margin="0 10 0 0" Click="btnCancel_Click"/><ListView Name="listView" Padding="0 10 0 0" Height="300"><ListView.ItemTemplate><DataTemplate><StackPanel Margin="0 5" Background="Blue"><TextBlock Text="{Binding Source}" Margin="5"/><TextBlock Text="{Binding Destination}" Margin="5"/><TextBlock Text="{Binding Progress}" Margin="5"/></StackPanel></DataTemplate></ListView.ItemTemplate></ListView></StackPanel></Grid></Page>
BackgroundTask/TransferDownload.xaml.cs
/* * 演示后台下载任务的应用 ** BackgroundDownloader - 后台下载任务管理器 * CostPolicy - 下载的成本策略,BackgroundTransferCostPolicy 枚举 * Default - 不允许在高成本(比如 2G 3G)网络上传输 * UnrestrictedOnly - 允许在高成本(比如 2G 3G)网络上传输 * Always - 无论如何均可传输,即使在漫游时 * ServerCredential - 与服务端通信时的凭据 * ProxyCredential - 使用代理时的身份凭据 * SetRequestHeader(string headerName, string headerValue) - 设置 http 请求头 * CreateDownload(Uri uri, IStorageFile resultFile) - 创建一个下载任务,返回 DownloadOperation 对象 * Group - 用于分组下载任务 * static GetCurrentDownloadsAsync(string group) - 获取指定组下的所有下载任务 * static GetCurrentDownloadsAsync() - 获取未与组关联的所有下载任务 ** DownloadOperation - 下载任务对象 * CostPolicy - 下载的成本策略,BackgroundTransferCostPolicy 枚举 * Group - 获取此下载任务的所属组 * Guid - 获取此下载任务的标识 * RequestedUri - 下载的源 URI * ResultFile - 下载的目标文件 * GetResponseInformation() - 下载完成后获取到的服务端响应信息,返回 ResponseInformation 对象 * ActualUri - 下载源的真实 URI * Headers - 服务端响应的 HTTP 头 * StatusCode - 服务端响应的状态码 * Pause() - 暂停此任务 * Resume() - 继续此任务 * StartAsync() - 新增一个下载任务,返回 IAsyncOperationWithProgress<DownloadOperation, DownloadOperation> 对象 * AttachAsync() - 监视已存在的下载任务,返回 IAsyncOperationWithProgress<DownloadOperation, DownloadOperation> 对象 * Progress - 获取下载进度,返回 BackgroundDownloadProgress 对象 ** BackgroundDownloadProgress - 后台下载任务的下载进度对象 * BytesReceived - 已下载的字节数 * TotalBytesToReceive - 总共需要下载的字节数,未知则为 0* Status - 下载状态,BackgroundTransferStatus 枚举 * Idle, Running, PausedByApplication, PausedCostedNetwork, PausedNoNetwork, Completed, Canceled, Error * HasResponseChanged - 服务端响应了则为 true * HasRestarted - 当下载连接断掉后,系统会通过 http range 头向服务端请求断点续传,如果服务端不支持断点续传则需要重新下载,此种情况则为 true */using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Threading;using System.Threading.Tasks;using System.Linq;using Windows.Networking.BackgroundTransfer;using Windows.Storage;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.Web;namespace XamlDemo.BackgroundTask{public sealed partial class TransferDownload : Page{// 下载任务的集合private ObservableCollection<TransferModel> _transfers = new ObservableCollection<TransferModel>();// 所有下载任务的关联的 CancellationTokenSource 对象private CancellationTokenSource _cancelToken = new CancellationTokenSource(); public TransferDownload(){this.InitializeComponent();Init();}private async void Init(){listView.ItemsSource = _transfers;// 获取全部下载任务await LoadDownloadAsync();}// 加载全部下载任务private async Task LoadDownloadAsync(){IReadOnlyList<DownloadOperation> downloads = null;try{// 获取所有后台下载任务downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();}catch (Exception ex){lblMsg.Text += ex.ToString();lblMsg.Text += Environment.NewLine;return;}if (downloads.Count > 0){List<Task> tasks = new List<Task>();foreach (DownloadOperation download in downloads){// 监视指定的后台下载任务tasks.Add(HandleDownloadAsync(download, false));}await Task.WhenAll(tasks);}}// 新增一个下载任务private async void btnAddDownload_Click(object sender, RoutedEventArgs e){// 下载地址(注意需要在 Package.appxmanifest 中增加对 .rar 类型文件的关联)// Uri sourceUri = new Uri("http://files.cnblogs.com/webabcd/Windows8.rar", UriKind.Absolute);StorageFile destinationFile;try{// 保存的目标地址destinationFile = await KnownFolders.DocumentsLibrary.CreateFileAsync("Windows8.rar", CreationCollisionOption.GenerateUniqueName);}catch (Exception ex){lblMsg.Text += ex.ToString();lblMsg.Text += Environment.NewLine;return;}// 创建一个后台下载任务BackgroundDownloader backgroundDownloader = new BackgroundDownloader();DownloadOperation download = backgroundDownloader.CreateDownload(sourceUri, destinationFile);// 监视指定的后台下载任务await HandleDownloadAsync(download, true);}/// <summary>/// 监视指定的后台下载任务/// </summary>/// <param name="download">后台下载任务</param>/// <param name="isNew">是否是新增的任务</param>private async Task HandleDownloadAsync(DownloadOperation download, bool isNew){try{// 将 DownloadOperation 附加到 TransferModel,以便下载进度可通知TransferModel transfer = new TransferModel();transfer.DownloadOperation = download;transfer.Source = download.RequestedUri.ToString();transfer.Destination = download.ResultFile.Path;transfer.Progress = "0 / 0";_transfers.Add(transfer);lblMsg.Text += "Task Count: " + _transfers.Count.ToString();lblMsg.Text += Environment.NewLine;// 当下载进度发生变化时的回调函数Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);if (isNew)await download.StartAsync().AsTask(_cancelToken.Token, progressCallback); // 新增一个后台下载任务elseawait download.AttachAsync().AsTask(_cancelToken.Token, progressCallback); // 监视已存在的后台下载任务// 下载完成后获取服务端的响应信息ResponseInformation response = download.GetResponseInformation();lblMsg.Text += "Completed: " + response.ActualUri + "-" + response.StatusCode.ToString();lblMsg.Text += Environment.NewLine;}catch (TaskCanceledException) // 调用 CancellationTokenSource.Cancel() 后会抛出此异常{lblMsg.Text += "Canceled: " + download.Guid;lblMsg.Text += Environment.NewLine;}catch (Exception ex){// 将异常转换为 WebErrorStatus 枚举,如果获取到的是 WebErrorStatus.Unknown 则说明此次异常不是涉及 web 的异常WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult);lblMsg.Text += ex.ToString();lblMsg.Text += Environment.NewLine;}finally{_transfers.Remove(_transfers.First(p => p.DownloadOperation == download));}}// 进度发生变化时,更新 TransferModel 的 Progress,以便通知private void DownloadProgress(DownloadOperation download){TransferModel transfer = _transfers.First(p => p.DownloadOperation == download);transfer.Progress = download.Progress.BytesReceived.ToString("#,0") + " / " + download.Progress.TotalBytesToReceive.ToString("#,0");}// 暂停全部后台下载任务private void btnPause_Click(object sender, RoutedEventArgs e){lblMsg.Text += "All Paused";lblMsg.Text += Environment.NewLine;foreach (TransferModel transfer in _transfers){if (transfer.DownloadOperation.Progress.Status == BackgroundTransferStatus.Running){transfer.DownloadOperation.Pause();}}}// 继续全部后台下载任务private void btnResume_Click(object sender, RoutedEventArgs e){lblMsg.Text += "All Resumed";lblMsg.Text += Environment.NewLine;foreach (TransferModel transfer in _transfers){if (transfer.DownloadOperation.Progress.Status == BackgroundTransferStatus.PausedByApplication){transfer.DownloadOperation.Resume();}}}// 取消全部后台下载任务private void btnCancel_Click(object sender, RoutedEventArgs e){_cancelToken.Cancel();_cancelToken.Dispose();_cancelToken = new CancellationTokenSource();}}}
2、演示后台上传任务的应用BackgroundTask/TransferUpload.xaml