代码改变世界
[登录 · 注册]
  • 背水一战 Windows 10 (118) 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知)
  • [源码下载]


    背水一战 Windows 10 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知)



    作者:webabcd


    介绍
    背水一战 Windows 10 之 后台任务

    • 后台下载任务(任务分组,并行或串行执行,组完成后通知)



    示例
    演示后台下载任务的分组,以及如何设置组内任务是并行执行还是串行执行,以及组任务全部完成后如何 toast 或 tile 通知)
    BackgroundTask/TransferModel.cs

    /*
     * 扩展了 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/TransferGroup.xaml

    <Page
        x:Class="Windows10.BackgroundTask.TransferGroup"
        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="新增一组(3 个)下载任务,可以指定其是并发还是串行,当这一组的所有任务都完成后弹出通知" Margin="5" Click="btnAddDownload_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/TransferGroup.xaml.cs

    /*
     * 演示后台下载任务的分组,以及如何设置组内任务是并行执行还是串行执行,以及组任务全部完成后如何 toast 或 tile 通知)
     * 
     * BackgroundTransferGroup - 后台下载任务的分组对象
     *     static BackgroundTransferGroup CreateGroup(string name) - 创建指定分组标识的 BackgroundTransferGroup 对象
     *     Name - 分组标识(只读)
     *     TransferBehavior - 组内下载任务的执行方式,BackgroundTransferBehavior 枚举
     *         Parallel - 并行
     *         Serialized - 串行
     * 
     * BackgroundDownloader - 后台下载任务管理器
     *     TransferGroup - 设置或获取分组对象(BackgroundTransferGroup 类型)
     *     static GetCurrentDownloadsForTransferGroupAsync(BackgroundTransferGroup group) - 获取指定组的所有下载任务
     *     
     * DownloadOperation - 下载任务对象
     *     TransferGroup - 获取此下载任务的分组对象(BackgroundTransferGroup 类型)
     */
    
    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.UI.Notifications;
    using Windows.Data.Xml.Dom;
    
    namespace Windows10.BackgroundTask
    {
        public sealed partial class TransferGroup : Page
        {
            // 用于后台任务的分组(通过组名标识后台任务)
            private BackgroundTransferGroup _group = BackgroundTransferGroup.CreateGroup("my_group");
    
            // 下载任务的集合
            private ObservableCollection<TransferModel> _transfers = new ObservableCollection<TransferModel>();
    
            // 所有下载任务的关联的 CancellationTokenSource 对象
            private CancellationTokenSource _cancelToken = new CancellationTokenSource();
    
            public TransferGroup()
            {
                this.InitializeComponent();
    
                Init();
            }
    
            private async void Init()
            {
                // 指定组内任务并行执行
                _group.TransferBehavior = BackgroundTransferBehavior.Parallel;
    
                listView.ItemsSource = _transfers;
    
                // 加载指定组的下载任务
                await LoadDownloadAsync();
            }
    
            // 加载指定组的下载任务
            private async Task LoadDownloadAsync()
            {
                IReadOnlyList<DownloadOperation> downloads = null;
                try
                {
                    // 获取指定组的下载任务
                    downloads = await BackgroundDownloader.GetCurrentDownloadsForTransferGroupAsync(_group);
                }
                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);
                }
            }
    
            // 新增一组(3 个)下载任务
            private async void btnAddDownload_Click(object sender, RoutedEventArgs e)
            {
                BackgroundDownloader backgroundDownloader = new BackgroundDownloader();
                // 指定分组
                backgroundDownloader.TransferGroup = _group;
                // 组任务全部成功后弹出指定的 toast 通知(类似的还有 SuccessTileNotification, FailureToastNotification, FailureTileNotification)
                backgroundDownloader.SuccessToastNotification = GetToastNotification(_group.Name);
    
                List<DownloadOperation> downloads = new List<DownloadOperation>();
                for (int i = 0; i < 3; i++)
                {
                    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;
                    }
                    // 创建一个后台下载任务
                    DownloadOperation download = backgroundDownloader.CreateDownload(sourceUri, destinationFile);
    
                    downloads.Add(download);
                }
    
                // 处理并监视组内的后台下载任务
                Task[] tasks = new Task[downloads.Count];
                for (int i = 0; i < downloads.Count; i++)
                {
                    tasks[i] = HandleDownloadAsync(downloads[i], true);
                }
    
                await Task.WhenAll(tasks);
    
            }
    
            /// <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 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);
            }
    
            private ToastNotification GetToastNotification(string groupName)
            {
                string toastXml = $@"
                    <toast activationType='foreground'>
                        <visual>
                            <binding template='ToastGeneric'>
                                <text>toast - title</text>
                                <text>组 {groupName} 中的下载任务全部完成了</text>
                            </binding>
                        </visual>
                    </toast>";
    
                XmlDocument toastDoc = new XmlDocument();
                toastDoc.LoadXml(toastXml);
    
                return new ToastNotification(toastDoc);
            }
        }
    }



    OK
    [源码下载]

  • 上一篇:背水一战 Windows 10 (119) 后台任务: 后台下载任务(任务分组,组完成后触发后台任务)
    下一篇:背水一战 Windows 10 (117) 后台任务: 后台下载任务
  • 【推广】 阿里云小站-上云优惠聚集地(新老客户同享)更有每天限时秒杀!
    【推广】 云服务器低至0.95折 1核2G ECS云服务器8.1元/月
    【推广】 阿里云老用户升级四重礼遇享6.5折限时折扣!
  • 原文:https://www.cnblogs.com/webabcd/p/9211752.html
走看看 - 开发者的网上家园