簡體   English   中英

C#downloadfileasync等待不凍結UI

[英]c# downloadfileasync wait without freezing ui

問題很簡單,但是我還沒有找到任何具體的文章。 我希望能夠異步下載文件,等待它完成,顯示進度條,然后從我在主線程中的位置繼續,而不是從文件完成引發事件繼續。 我需要異步下載文件,因為我需要顯示進度條。 而且我不得不使用.NET 2.0。

我發現的所有頁面都在解決這個問題,只需將DownloadFileAsync作為最后一個命令運行,因此沒有更多可運行的方式了……這種方式很簡單,因為當downloadfilecompleted觸發時執行“繼續”。 我搜索的所有樣本全部都以這種方式工作。

但是我需要保留在主線程上 ,等待,讓downloadprogresschanged訪問UI來更新進度條,然后從那里繼續。

像這樣:

private ManualResetEvent myMREDown = new ManualResetEvent(false);

WebClient myClient = new WebClient();
myClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(myClient_DownloadProgressChanged);
   myClient.DownloadFileCompleted += new AsyncCompletedEventHandler(myClient_DownloadFileCompleted);

myClient.DownloadFileAsync(SomeURL);
mre_DownloadingFile.WaitOne();
ContinueDoingSomethingElse(); // <-- I want to reach THIS point after download

void myClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
  {
//update the progress bar
}

void myClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
  {
mre_DownloadingFile.Set();
}

現在,我的問題是:

A)一般來說,如果我只運行DownloadFileAsync,我了解下載是在單獨的線程中進行的,因為如果在此之后編寫更多代碼,它將在不等待DownloadFileAsync完成的情況下運行...但是,如果我等待一個()在我的主線程中,該下載線程似乎已掛起,因為它沒有顯示任何進度條...所以...它是與我的線程不在同一線程上?

B)如果我將整個下載過程包裝到一個方法中,然后使用Start New Thread()運行它,然后使用ManualResetEvent Waitone(),則UI凍結相同...

C)最重要的是...是否有出路? (如果可能,也請提供代碼)

好的,我深入探討了這個問題,因此我會回答自己,希望這對我有同樣的疑問可以幫助其他人。

回答:

A)一般來說,如果我只運行DownloadFileAsync,我了解下載是在單獨的線程中進行的,因為如果在此之后編寫更多代碼,它將在不等待DownloadFileAsync完成的情況下運行...但是,如果我等待一個()在我的主線程中,該下載線程似乎已掛起,因為它沒有顯示任何進度條...所以...它是與我的線程不在同一線程上?

問題是:您不能等待主UI線程。 這意味着,在您運行該程序時,它通常會在可以訪問UI的線程上運行。 因此,無論您做什么以及如何做,如果在那里的WaitOne(),UI都會凍結。 沒有辦法。 保持原樣。 當您運行DownloadFileAsync時,它會產生一個新線程,但是由於從那里嘗試更新主線程上的進度條,因此如果該線程正在等待,它將無法執行任何操作。 所以問題又來了,您不能等待主線程。

B)如果我將整個下載過程包裝到一個方法中,然后使用Start New Thread()運行它,然后使用ManualResetEvent Waitone(),則UI凍結相同...

原因與點A)相同-即使您啟動了一個新線程,但隨后在主線程UI上等待,您將無處可去。

C)最重要的是...是否有出路? (如果可能,也請提供代碼)

是的,解決方案是:以不同的方式考慮您的程序。 由於您不能在那里等待,因此您需要重新編碼所有內容,以便您必須能夠運行asyncdownload,放棄之前一直在執行的程序邏輯,然后在其他位置繼續進行操作(在我的案例中是DownloadFileCompleted事件)。 例如,您可以在新線程上運行所有內容,使用委托更新進度條(這樣他們將從正確的線程調用UI更新),然后從該新線程甚至可以使用Wait(),因為將等待放在另一個線程上,這不是主要線程。

就我而言,我有一個要執行的命令列表...因此,我首先創建了一個隊列並在其中添加了所有命令,然后創建了一種“ RunNextCommand”方法,該方法使Element出隊並運行該命令,並且如果其中一個命令是“ downloadafile”,那么我只運行asyncdownload,然后從DownloadFileCompleted事件中再運行一個“ RunNextCommand”。

這樣,您就不會使用DoEvents()(這總是一個非常糟糕的主意),您的CPU不會100%運行,並且您的代碼漂亮干凈;-)

謝謝你自己。 不客氣 再見。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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