![](/img/trans.png)
[英]DownloadFileCompleted event doesn't fire inside while loop c# .net
[英]DownloadFileCompleted doesn't work immediately after a download-completed event in C# winform?
開發環境:
C#,Visual Studio 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事件?
我建議使用與其他問題類似的方法“ 如何在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);
我認為問題在於,將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();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.