簡體   English   中英

在C#winform中完成下載事件后,DownloadFileCompleted不能立即工作嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM