背水一战 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 > )
{
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 = ; i < ; 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 = ; 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(, 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 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知)的更多相关文章
- 背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务)
[源码下载] 背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务) 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下 ...
- 背水一战 Windows 10 (117) - 后台任务: 后台下载任务
[源码下载] 背水一战 Windows 10 (117) - 后台任务: 后台下载任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务 示例演示 uwp 的后台下 ...
- 背水一战 Windows 10 (120) - 后台任务: 后台上传任务
[源码下载] 背水一战 Windows 10 (120) - 后台任务: 后台上传任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台上传任务 示例演示 uwp 的后台上 ...
- 背水一战 Windows 10 (121) - 后台任务: 推送通知
[源码下载] 背水一战 Windows 10 (121) - 后台任务: 推送通知 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 推送通知 示例演示如何接收推送通知/WebA ...
- 背水一战 Windows 10 (115) - 后台任务: 通过 toast 激活后台任务, 定时激活后台任务
[源码下载] 背水一战 Windows 10 (115) - 后台任务: 通过 toast 激活后台任务, 定时激活后台任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 通 ...
- 背水一战 Windows 10 (116) - 后台任务: 前台程序激活后台任务
[源码下载] 背水一战 Windows 10 (116) - 后台任务: 前台程序激活后台任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 前台程序激活后台任务 示例演示后 ...
- 背水一战 Windows 10 (114) - 后台任务: 后台任务的 Demo(与 app 不同进程), 后台任务的 Demo(与 app 相同进程)
[源码下载] 背水一战 Windows 10 (114) - 后台任务: 后台任务的 Demo(与 app 不同进程), 后台任务的 Demo(与 app 相同进程) 作者:webabcd 介绍背水一 ...
- 背水一战 Windows 10 (67) - 控件(控件基类): DependencyObject - CoreDispatcher, 依赖属性的设置与获取, 依赖属性的变化回调
[源码下载] 背水一战 Windows 10 (67) - 控件(控件基类): DependencyObject - CoreDispatcher, 依赖属性的设置与获取, 依赖属性的变化回调 作者: ...
- 背水一战 Windows 10 (59) - 控件(媒体类): Image, MediaElement
[源码下载] 背水一战 Windows 10 (59) - 控件(媒体类): Image, MediaElement 作者:webabcd 介绍背水一战 Windows 10 之 控件(媒体类) Im ...
随机推荐
- Hillstone设备管理-设备软件Stone-OS升级
1.通过sysloader进行StoneOS升级 1)给设备上电按提示按ESC并且进入 Sysloader.参照以下操作提示: 2)在下面选择对应的选项升级os,可以通过tftp.ftp.usb.系统 ...
- Spring Boot HikariCP 一 ——集成多数据源
其实这里介绍的东西主要是参考的另外一篇文章,数据库读写分离的. 参考文章就把链接贴出来,里面有那位的代码,简单明了https://gitee.com/comven/dynamic-datasource ...
- shell中脚本调试----学习
1.使用dos2unix命令处理在windows下开发的脚本 将windows下编辑的脚本放置到linux下执行的情况如下: [root@ks ~]# cat -v nginx.sh #!/bin/b ...
- ARM汇编指令格式
一.ARM介绍 1) arm汇编中,程序下一步执行哪一条指令,是根据程序计数器(PC)的值来决定. 类比于8086的CS:IP的功能. 2) 8086属于CISC(复杂指令集),每条指令长度不等,ar ...
- WebSocket入门及示例
前言 一直在想要不要写下这篇,因为网上关于websocket的介绍和使用的好文实在太多太多,例如有这篇和这篇. 但我不管了,写下来,这样我就不用在想使用的时候总是去翻写过的源码了. 先回答几个简单的问 ...
- centos7 端口3306无法连接问题
MySQL建用户的时候会指定一个host,默认是127.0.0.1/localhost,那么这个用户就只能本机访问,其它机器用这个用户帐号访问会提示没有权限,host改为%,表示允许所有机器访问. G ...
- Linux 学习笔记 2:文件系统
1.文件系统层次结构 系统目录内容: /: 根目录(之后的/都是目录分隔符) /home:用户目录 /bin: Unix常用命令,如bash, date, cat, tar等 /sbin: 管理员命令 ...
- linux 网络虚拟化: network namespace 简介
linux 网络虚拟化: network namespace 简介 network namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息.不管是虚拟机还是 ...
- 探索未知种族之osg类生物---渲染遍历之裁剪一
前言 上面我们用了四节课的内容,讲解了一些osg概念性的内部原理.希望大家可以再看今天的讲解之前先再仔细的研究一下前四节的内容.这样你就会对整个osg的渲染过程有一个更加清晰的认知,有助于理解下面两个 ...
- 真机测试没有问题,but上线后安装在手机上crash。也有无法打包的情况。
图片格式不对,把16位or p3图片改为8位sRGB图片 9.0以前不支持 解决步骤: a.找到导出项目的ipa文件修改后缀名.ipa为.zip后直接解压该文件: b.找到出问题的图片,直接把该图片 ...