背水一戰 Windows 10 (117) - 後臺任務: 後臺下載任務

[源碼下載]


html

背水一戰 Windows 10 (117) - 後臺任務: 後臺下載任務



做者:webabcd


介紹
背水一戰 Windows 10 之 後臺任務html5

  • 後臺下載任務



示例
演示 uwp 的後臺下載任務
BackgroundTask/TransferModel.csc++

/*
 * 擴展了 DownloadOperation 和 UploadOperation,用於 MVVM 綁定數據
 */

using System;
using System.ComponentModel;
using Windows.Networking.BackgroundTransfer;

namespace Windows10.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));
            }
        }
    }
}

BackgroundTask/TransferDownload.xamlweb

<Page
    x:Class="Windows10.BackgroundTask.TransferDownload"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.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="10 0 10 10">

            <ScrollViewer Name="scrollViewer" Height="100" Margin="5">
                <TextBlock Name="lblMsg" TextWrapping="Wrap" />
            </ScrollViewer>

            <Button Name="btnAddDownload" Content="新增一個下載任務" Margin="5" Click="btnAddDownload_Click" />
            <Button Name="btnPause" Content="暫停全部下載任務" Margin="5" Click="btnPause_Click" />
            <Button Name="btnResume" Content="繼續全部下載任務" Margin="5" Click="btnResume_Click" />
            <Button Name="btnCancel" Content="取消全部下載任務" Margin="5" Click="btnCancel_Click" />

            <ListView Name="listView" Height="286" Padding="5">
                <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.csexpress

/*
 * 演示 uwp 的後臺下載任務
 * 
 * BackgroundDownloader - 後臺下載任務管理器
 *     CreateDownload(Uri uri, IStorageFile resultFile) - 建立一個下載任務,返回 DownloadOperation 對象
 *     SetRequestHeader(string headerName, string headerValue) - 設置 http 請求頭
 *     Method - 用於下載的 http method(默認 get)
 *     static GetCurrentDownloadsAsync() - 獲取當前 app 的未與組關聯的全部下載任務
 *     CostPolicy - 下載的成本策略,BackgroundTransferCostPolicy 枚舉
 *         Default - 容許在高成本(好比 4G)網絡上傳輸(默認值)
 *         UnrestrictedOnly - 不容許在高成本(好比 4G)網絡上傳輸
 *         Always - 不管如何都可傳輸,即便在漫遊時
 *     ServerCredential - 與服務端通訊時的憑據
 *     ProxyCredential - 使用代理時的身份憑據
 *     SuccessToastNotification, SuccessTileNotification, FailureToastNotification, FailureTileNotification - 下載任務成功或失敗後的 toast 或 tile 通知
 *     
 * DownloadOperation - 下載任務對象
 *     Guid - 獲取此下載任務的標識
 *     CostPolicy - 下載的成本策略,BackgroundTransferCostPolicy 枚舉
 *     RequestedUri - 下載的源 URI
 *     ResultFile - 下載的目標文件
 *     Method - 獲取用於下載的 http method(get, post 之類的)
 *     GetResponseInformation() - 下載完成後獲取到的服務端響應信息,返回 ResponseInformation 對象
 *         ActualUri - 下載源的真實 URI
 *         Headers - 服務端響應的 HTTP 頭
 *         StatusCode - 服務端響應的狀態碼
 *     Pause() - 暫停此下載任務
 *     Resume() - 繼續此下載任務
 *     StartAsync() - 新增一個下載任務,返回 IAsyncOperationWithProgress<DownloadOperation, DownloadOperation> 對象
 *     AttachAsync() - 監視已存在的下載任務,返回 IAsyncOperationWithProgress<DownloadOperation, DownloadOperation> 對象
 *     Progress - 獲取下載進度,返回 BackgroundDownloadProgress 對象
 *     Priority - 下載的優先級,BackgroundTransferPriority 枚舉
 *         Default 或 High
 *     
 * 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;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;

namespace Windows10.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)
            {
                WriteLine(ex.ToString());
                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)
        {
            Uri sourceUri = new Uri("http://files.cnblogs.com/webabcd/Windows10.rar", UriKind.Absolute);

            StorageFile destinationFile;
            try
            {
                // 保存的目標地址(別忘了在 Package.appxmanifest 中配置好 <Capability Name="documentsLibrary" /> 和 .rar 類型文件的關聯)
                StorageFolder storageFolder = await KnownFolders.GetFolderForUserAsync(null, KnownFolderId.DocumentsLibrary);
                destinationFile = await storageFolder.CreateFileAsync("Windows10.rar", CreationCollisionOption.GenerateUniqueName);
            }
            catch (Exception ex)
            {
                WriteLine(ex.ToString());
                return;
            }
            
            BackgroundDownloader backgroundDownloader = new BackgroundDownloader();
            // 任務成功後彈出指定的 toast 通知(相似的還有 SuccessTileNotification, FailureToastNotification, FailureTileNotification)
            backgroundDownloader.SuccessToastNotification = GetToastNotification(sourceUri);
            // 建立一個後臺下載任務
            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
            {
                // 構造顯示用的相關數據
                TransferModel transfer = new TransferModel();
                transfer.DownloadOperation = download;
                transfer.Source = download.RequestedUri.ToString();
                transfer.Destination = download.ResultFile.Path;
                transfer.Progress = download.Progress.Status.ToString() + ": 0 / 0";

                _transfers.Add(transfer);

                WriteLine("Task Count: " + _transfers.Count.ToString());

                // 當下載進度發生變化時的回調函數
                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();
                WriteLine("Completed: " + response.ActualUri + ", HttpStatusCode: " + response.StatusCode.ToString());
            }
            catch (TaskCanceledException) // 調用 CancellationTokenSource.Cancel() 後會拋出此異常
            {
                WriteLine("Canceled: " + download.Guid);
            }
            catch (Exception ex)
            {
                // 將異常轉換爲 WebErrorStatus 枚舉,若是獲取到的是 WebErrorStatus.Unknown 則說明這次異常不是涉及 web 的異常
                WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult);

                WriteLine(ex.ToString());
            }
            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.Status.ToString() + ": " + download.Progress.BytesReceived.ToString("#,0") + " / " + download.Progress.TotalBytesToReceive.ToString("#,0");
        }

        // 暫停所有後臺下載任務
        private void btnPause_Click(object sender, RoutedEventArgs e)
        {
            WriteLine("All Paused");
            foreach (TransferModel transfer in _transfers)
            {
                transfer.DownloadOperation.Pause();
            }
        }

        // 繼續所有後臺下載任務
        private void btnResume_Click(object sender, RoutedEventArgs e)
        {
            WriteLine("All Resumed");
            foreach (TransferModel transfer in _transfers)
            {
                transfer.DownloadOperation.Resume();
            }
        }

        // 取消所有後臺下載任務
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            _cancelToken.Cancel();
            _cancelToken.Dispose();

            _cancelToken = new CancellationTokenSource();
        }

        // 向 lblMsg 中追加一行文本
        private void WriteLine(string message)
        {
            lblMsg.Text += message;
            lblMsg.Text += Environment.NewLine;

            scrollViewer.ChangeView(0, scrollViewer.ScrollableHeight, 1f);
        }
        
        // 構造指定的 toast 通知
        private ToastNotification GetToastNotification(Uri sourceUri)
        {
            string toastXml = $@"
                <toast activationType='foreground'>
                    <visual>
                        <binding template='ToastGeneric'>
                            <text>toast - title</text>
                            <text>下載任務成功完成</text>
                            <text>{sourceUri}</text>
                        </binding>
                    </visual>
                </toast>";
            
            XmlDocument toastDoc = new XmlDocument();
            toastDoc.LoadXml(toastXml);

            return new ToastNotification(toastDoc);
        }
    }
}



OK
[源碼下載]windows

相關文章
相關標籤/搜索