发展环境:
C#,2010 (.net 4.0),win7 x64
winform项目代码:
private void Form1_Load(object sender, EventArgs e)
{
string path = "c:\\1.jpg";
for (int i = 0; i < 10; i++)
{
string url = "http://...." + i.ToString() + ".jpg";//i'm sure the http file does exist
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(new Uri(url), path);
Thread.Sleep(3000);//i'm sure the download will be finished in 3s
WriteLog("C:\\1.log", "main function\r\n");
}
}
}
static void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
WriteLog("C:\\1.log", "callback function\r\n");
}
static void WriteLog(string LogName, string log)
{
StreamWriter sw = new StreamWriter(LogName, true);
if (sw == null)
return;
sw.Write(System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " " + log);
sw.Close();
}然后日志将是:
2017/11/03 19:04:48主要职能 2017/11/03 19:04:51主要职能 2017/11/03 19:04:54主要职能 2017/11/03 19:04:57项主要职能 2017/11/03 19:05:00主要职能 2017/11/03 19:05:03主要职能 2017/11/03 19:05:06主要职能 2017/11/03 19:05:09主要职能 2017/11/03 19:05:12主要职能 2017/11/03 19:05:15主要职能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能 2017/11/03 19:05:15回调功能
如果ConsoleApplication中相同的代码:
static void Main(string[] args)
{
string path = "c:\\1.jpg";
for (int i = 0; i < 10; i++)
{
string url = "http://...." + i.ToString() + ".jpg";//i'm sure the http file does exist
using (WebClient wc= new WebClient())
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(new Uri(url), path);
Thread.Sleep(3000);//i'm sure the download will be finished in 3s
WriteLog("C:\\1.log", "main function\r\n");
}
}
}
static void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
WriteLog("C:\\1.log", "callback function\r\n");
}
static void WriteLog(string LogName, string log)
{
StreamWriter sw = new StreamWriter(LogName, true);
if (sw == null)
return;
sw.Write(System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " " + log);
sw.Close();
}然后日志将是:
2017/11/03 19:13:50个回调功能 2017/11/03 19:13:52项主要职能 2017/11/03 19:13:53回调功能 2017/11/03 19:13:55主要职能 2017/11/03 19:13:56回调功能 2017/11/03 19:13:58项主要职能 2017/11/03 19:13:59回调功能 2017/11/03 19:14:01主要职能 2017/11/03 19:14:02回调功能 2017/11/03 19:14:04主要职能 2017/11/03 19:14:05回调功能 2017/11/03 19:14:08主要职能 2017/11/03 19:14:08回调功能 2017/11/03 19:14:11主要职能 2017/11/03 19:14:11回调功能 2017/11/03 19:14:14主要职能 2017/11/03 19:14:14个回调功能 2017/11/03 19:14:17主要职能 2017/11/03 19:14:17回调功能 2017/11/03 19:14:20主要职能
显然,第二个结果是正确的。
但是在第一个项目中,为什么在所有下载完成之前不调用DownloadFileCompleted事件?
如何在每次下载完成后立即调用DownloadFileCompleted事件?
发布于 2017-11-03 12:30:33
我认为问题在于DownloadFileCompleted事件与表单的Load事件放在同一个事件队列中,因此在Form1_Load完成之前不能处理它。
通常,阻塞UI线程(比如睡在Form1_Load中)是一种糟糕的做法。耗时的代码应该在后台线程中运行。以下是这样做的一种方法:
private void Form1_Load(object sender, EventArgs e)
{
new Thread(() =>
{
string path = "c:\\1.jpg";
for (int i = 0; i < 10; i++)
{
string url = "http://...." + i.ToString() + ".jpg";//i'm sure the http file does exist
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(new Uri(url), path);
Thread.Sleep(3000);//i'm sure the download will be finished in 3s
WriteLog("C:\\1.log", "main function\r\n");
}
}
}).Start();
}使用此方法,即使在窗体关闭后后台线程也不会退出(应用程序只有在后台线程完成其工作后才会终止),这可能是您想要的,也可能不是您想要的。
如果希望在窗体关闭时终止后台线程,则可以使用BackgroundWorker,这还为您提供了其他方便的功能,如报告进度和取消:
private void Form1_Load(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender_, e_) =>
{
string path = "c:\\1.jpg";
for (int i = 0; i < 10; i++)
{
string url = "http://...." + i.ToString() + ".jpg";//i'm sure the http file does exist
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(new Uri(url), path);
Thread.Sleep(3000);//i'm sure the download will be finished in 3s
WriteLog("C:\\1.log", "main function\r\n");
}
}
};
worker.RunWorkerAsync();
}发布于 2017-11-03 12:00:10
我建议使用类似于另一个问题"如何在WebClient.DownloadFileAsync上实现超时“的方法
看起来,thread.sleep导致写入日志的线程休眠。这样你就不会发生这种情况,而且它是非阻塞的,所以没有线程会被困住,忙着等待。
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(TimeSpan.FromSeconds(5));
await Task.Factory.StartNew(() =>
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFile(new Uri("MyInternetFile"), filePath);
}, source.Token);https://stackoverflow.com/questions/47094815
复制相似问题