继上一篇 一个简单的利用 WebClient 异步下载的示例(一) 后,我想把核心的处理提取出来,成 SkyWebClient,如下:

1. SkyWebClient

该构造函数中 downloadConfigs 参数是必须的,不能为 NULL,而 ProgressBar progressBar 可为空,只不过不能显示进度条而已。

    public class DownloadEntry
{
public string Url { get; set; } public string Path { get; set; } /// <summary>
/// 当前处理的数据
/// </summary>
public object Data { get; set; } public DownloadEntry(string url, string savedPath)
:this(url,savedPath, null)
{ } public DownloadEntry(string url, string savedPath, object data)
{
Url = url;
Path = savedPath;
Data = data;
}
} /// <summary>
/// 当单个下载前的事件处理
/// </summary>
/// <param name="current">当前处理的数据,有可能为 NULL,请注意判断</param>
public delegate void WhenSingleDownloadingEventHandler(DownloadEntry current); /// <summary>
/// 当全部下载完毕后的事件处理
/// </summary>
public delegate void WhenAllDownloadedEventHandler(); /// <summary>
/// 当下载错误时
/// </summary>
/// <param name="ex"></param>
public delegate void WhenDownloadingErrorEventHandler(Exception ex); public class SkyWebClient : INotifyPropertyChanged
{
#region 字段、属性 public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
} /// <summary>
/// 当单个下载前的事件处理
/// </summary>
public event WhenSingleDownloadingEventHandler WhenSingleDownloading;
private void OnWhenSingleDownloading(DownloadEntry next)
{
if (WhenSingleDownloading != null)
{
WhenSingleDownloading(next);
}
} /// <summary>
/// 当全部下载完毕后的事件处理
/// </summary>
public event WhenAllDownloadedEventHandler WhenAllDownloaded;
private void OnWhenAllDownloaded()
{
if (WhenAllDownloaded != null)
{
WhenAllDownloaded();
}
} /// <summary>
/// 当全部下载完毕后的事件处理
/// </summary>
public event WhenDownloadingErrorEventHandler WhenDownloadingError;
private void OnWhenDownloadingError(Exception ex)
{
if (WhenDownloadingError != null)
{
WhenDownloadingError(ex);
}
} ProgressBar progressBar;
WebClient webc;
Queue<DownloadEntry> ToDownload = new Queue<DownloadEntry>(); bool _canChange = true;
public bool CanChange
{
get
{
return _canChange;
}
set
{
_canChange = value;
OnPropertyChanged("CanChange");
}
} #endregion public SkyWebClient(IEnumerable<DownloadEntry> downloadConfigs)
:this(downloadConfigs, null)
{ } public SkyWebClient(IEnumerable<DownloadEntry> downloadConfigs, ProgressBar progressBar)
{
if (downloadConfigs == null)
{
throw new ArgumentNullException("downloadConfigs");
}
foreach (DownloadEntry item in downloadConfigs)
{
ToDownload.Enqueue(item);
}
this.webc = new WebClient();
this.progressBar = progressBar; webc.DownloadFileCompleted += Webc_DownloadFileCompleted; //注册下载完成事件
webc.DownloadProgressChanged += Webc_DownloadProgressChanged; //注册下载进度改变事件
} public void Start()
{
if (ToDownload.Count == )
{
Downloaded();
return;
}
if (CanChange)
{
CanChange = false;
if (this.progressBar != null)
{
this.progressBar.Maximum = ToDownload.Count * ;
}
StartCore();
}
else
{
ToDownload.Clear();
webc.CancelAsync();
CanChange = true;
//this.progressBar.Value = 0;
//btnRunByWebClient.Text = "用 WebClient 开始下载";
}
} private void StartCore()
{
DownloadEntry next = ToDownload.Dequeue();
webc.DownloadFileAsync(new Uri(next.Url), next.Path);
OnWhenSingleDownloading(next);
} private void DownloadNext()
{
if (ToDownload.Any())
{
StartCore();
if (this.progressBar != null)
{
this.progressBar.Value = this.progressBar.Maximum - ((ToDownload.Count + ) * );
}
}
else
{
if (this.progressBar != null)
{
this.progressBar.Value = ;
}
Downloaded();
}
} private void Downloaded()
{
CanChange = true;
OnWhenAllDownloaded();
} private void Webc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null && !e.Cancelled)
{
OnWhenDownloadingError(e.Error);
CanChange = true;
//this.progressBar.Value = 0;
}
else
{
DownloadNext();
}
} private void Webc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
if (this.progressBar != null)
{
this.progressBar.Value = this.progressBar.Maximum - ((ToDownload.Count + ) * ) + e.ProgressPercentage;
}
}
}

2. Form1.cs

在点击事件中,调用 SkyWebClient。

    public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private List<int> GetDownloadIds()
{
List<int> ids = new List<int>();
for (int i = ; i <= ; i++)
{
ids.Add(i);
}
return ids;
} private void WhenAllDownloading()
{
this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},准备开始下载...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
//禁用按钮
EnableOrDisableButtons(false);
} private void EnableOrDisableButtons(bool enabled)
{
this.btnRunByHttpClient.Enabled = enabled;
this.btnRunByWebClient.Enabled = enabled;
} private void WhenSingleDownloaded(int id, bool singleDownloadSuccess)
{
this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},编号 {1} 下载 {2}!", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), id, singleDownloadSuccess));
} private void WhenAllDownloaded()
{
this.listBoxLog.Items.Insert(, string.Format("当前时间:{0},下载完毕!", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
//启用按钮
EnableOrDisableButtons(true);
} private async void btnRunByHttpClient_Click(object sender, EventArgs e)
{
SkyHttpClient skyHttpClient = new SkyHttpClient();
try
{
WhenAllDownloading();
foreach (var id in GetDownloadIds())
{
bool singleDownloadSuccess = await TaskDemo101.RunByHttpClient(skyHttpClient, id);
WhenSingleDownloaded(id, singleDownloadSuccess);
}
WhenAllDownloaded();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Download Error!");
}
} private void btnRunByWebClient_Click(object sender, EventArgs e)
{
WhenAllDownloading();
var ids = GetDownloadIds();
List<DownloadEntry> downloadConfigs = new List<DownloadEntry>();
Random rd = new Random();
foreach (var id in ids)
{
downloadConfigs.Add(new DownloadEntry(TaskDemo101.GetRandomUrl(rd), TaskDemo101.GetSavedFileFullName(), id));
}
SkyWebClient skyWebClient = new SkyWebClient(downloadConfigs, this.progressBar1);
skyWebClient.WhenAllDownloaded += SkyWebClient_WhenAllDownloaded;
skyWebClient.WhenSingleDownloading += SkyWebClient_WhenSingleDownloading;
skyWebClient.WhenDownloadingError += SkyWebClient_WhenDownloadingError;
skyWebClient.Start();
} private void SkyWebClient_WhenDownloadingError(Exception ex)
{
MessageBox.Show("下载时出现错误: " + ex.Message);
} private void SkyWebClient_WhenSingleDownloading(DownloadEntry current)
{
WhenSingleDownloaded((int)current.Data, true);
} private void SkyWebClient_WhenAllDownloaded()
{
btnRunByWebClient.Text = "用 WebClient 开始下载";
WhenAllDownloaded();
} }

3. 运行截图

如图:

4. 总结

由于本下载采用依次来异步下载,虽然可以保证下载的文件的完整,但单位时间内效率不高,可能进度缓慢。且如果其中一个占用了较多的时间(比如:2分钟),那么整体的下载进度就会变慢。接下来,我会逐步优化它,敬请关注!

谢谢浏览!

一个简单的利用 WebClient 异步下载的示例(二)的更多相关文章

  1. 一个简单的利用 WebClient 异步下载的示例(三)

    继续上一篇 一个简单的利用 WebClient 异步下载的示例(二) 后,继续优化它. 1. 直接贴代码了: DownloadEntry: public class DownloadEntry { p ...

  2. 一个简单的利用 WebClient 异步下载的示例(一)

    继上一篇文章 一个简单的利用 HttpClient 异步下载的示例 ,我们知道不管是 HttpClient,还算 WebClient,都不建议每次调用都 new HttpClient,或 new We ...

  3. 一个简单的利用 WebClient 异步下载的示例(五)(完结篇)

    接着上一篇,我们继续来优化.我们的 SkyParallelWebClient 可否支持切换“同步下载模式”和“异步下载模式”呢,好处是大量的代码不用改,只需要调用 skyParallelWebClie ...

  4. 一个简单的利用 WebClient 异步下载的示例(四)

    接上一篇,我们继续优化它. 1. DownloadEntry 类 public class DownloadEntry { public string Url { get; set; } public ...

  5. 一个简单的利用 HttpClient 异步下载的示例

    可能你还会喜欢 一个简单的利用 WebClient 异步下载的示例  ,且代码更加新. 1. 定义自己的 HttpClient 类. using System; using System.Collec ...

  6. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(二)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(二) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 前: ...

  7. 一个简单的AXIS远程调用Web Service示例

    我们通常都将编写好的Web Service发布在Tomcat或者其他应用服务器上,然后通过浏览器调用该Web Service,返回规范的XML文件.但是如果我们不通过浏览器调用,而是通过客户端程序调用 ...

  8. [c#]WebClient异步下载文件并显示进度

    摘要 在项目开发中经常会用到下载文件,这里使用winform实现了一个带进度条的例子. 一个例子 using System; using System.Collections.Generic; usi ...

  9. WebClient异步下载文件

    namespace ConsoleAppSyncDownload{    class Program    { static void Main(string[] args)        {     ...

随机推荐

  1. idea设置类注释和方法注释

    类注释 1.file-->setting-->editor-->file and code templates-->includes--> file header 2.在 ...

  2. 简单的计时器 (倒计时)--html Demo

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content ...

  3. SQLserver创建用户和给用户权限(学)

    数据库基础知识:http://blog.csdn.net/u014600432/article/details/39645701 在SQL Server中创建用户角色及授权(使用SQL语句):http ...

  4. C++ 手把手教你实现可变长的数组

    01 实现自定义的可变长数组类型 假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的. int main() { MyArray a ...

  5. DesignPattern系列__09设计模式概述

    设计模式介绍 设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通用解决方案, 设计模(Design pattern)代表了最佳的实践.这些解决方案是众多软 ...

  6. js动态设置padding-top遇到的坑

    我想通过js动态设置元素padding-top的百分比值:以下几种都是无法设置成功的: // setAttribute设置padding-top并且转换为百分比 imageBox.setAttribu ...

  7. Javascript中的几种函数

    (1)普通函数:这种函数是我们日常使用中用的最多的,用function关键字定义的函数.这也是符合多种语言定义的. function foo(){ // code } (2)箭头函数:用=>运算 ...

  8. QT5.5+VS2013编译安装QtCharts (ZZ)

    环境 1.Windows 10 -x64: 2.MSVC 2013 -x64: 3.Qt5.5.1 -x86 and -x64. 编译过程 准备工作 1.安装ActivePerl 安装过程同一般软件安 ...

  9. 一次Ubuntu16系统的找回root密码的过程

    一 背景知识介绍 ubuntn系统的默认配置,超级用户root的密码是随机的,如果没提前对root用户的密码进行设置, 是不能直接通过root的身份来进行某些操作的,必须使用sudo命令,并通过普通用 ...

  10. 类,接口,final

    继承extends 子类实例化过程: 子类中所有的构造方法默认都会访问父类中空参的构造方法 因为每一个子类的构造方法的提议行都有一条默认的语句super(); this super final修饰类, ...