介紹
重新想象 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
<Page x: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 類型檔案的關聯)// 查看本欄目更多精彩內容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/net/ 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); // 新增一個後台下載任務 else await 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