简体   繁体   中英

c# downloadfileasync wait without freezing ui

The problem is very simple, yet I haven't found any specific article. I want to be able to download a file async, wait until it completes, show a progress bar, but then continue from the point where I was in the main thread, and NOT from the filecompleted raised event. I need the file download to be async because I need to show a progress bar. And I'm forced to use .NET 2.0.

All the pages I found are solving this problem simply running the DownloadFileAsync as the last command, so there's nothing more to run... this way is simple, because the execution "continues" when the downloadfilecompleted triggers. All, all, all the samples I searched are working this way.

But what I need is to remain on the main thread , wait, let the downloadprogresschanged access the UI to update a progressbar, and then continue from there.

Something like this:

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();
}

Now, my questions are:

A) Generally speaking, if I just run DownloadFileAsync, I understand the download happens in a separate thread, because if I write some more code after that, it will be run without waiting for the DownloadFileAsync to complete... however, if I WaitOne() from my main thread, that download thread seems to hung, because it doesn't shows any progress bar... So... it's on a separate thread from mine or not ???

B) If I wrap the entire download process into a method and then I use Start New Thread() to run it, and after that I use a ManualResetEvent Waitone(), the UI freezes the same...

C) Most of all... is there a wayout ???? (please providing code too, if possibile)

Ok I went deep on the problem and so I'll reply to myself, I hope this will help someone else with my same doubts.

Answers:

A) Generally speaking, if I just run DownloadFileAsync, I understand the download happens in a separate thread, because if I write some more code after that, it will be run without waiting for the DownloadFileAsync to complete... however, if I WaitOne() from my main thread, that download thread seems to hung, because it doesn't shows any progress bar... So... it's on a separate thread from mine or not ???

The problem is: you can't wait on the main UI thread. That means that when you run the program, it normally runs on a thread that is the one that has access to the UI. So, no matter what you do and how, if you WaitOne() there, your UI will freeze. No wayout to this. Keep it as it is. When you run the DownloadFileAsync it SPAWNS a new thread, but since from there you are trying to update a progress bar that is on the main thread, if that thread is waiting, it will not be able to do anything. So the problem is, again, you can't wait on the main thread.

B) If I wrap the entire download process into a method and then I use Start New Thread() to run it, and after that I use a ManualResetEvent Waitone(), the UI freezes the same...

The reason is the same of point A) - even if you start a new thread, but then you wait on the main thread UI, you'll not be able to go anywhere.

C) Most of all... is there a wayout ???? (please providing code too, if possibile)

Yes, the solution is: think your program differently. Since you can't wait there, you need to recode everything so that you must be able to run the asyncdownload, abandon the program logic you were doing until then, and continue it elsewhere (from the DownloadFileCompleted event in my case). You could for example run everything on a new thread, update the progress bar using delegates (so they'll call UI updates from the right thread), and then from this new thread you'll be able even to Wait(), because this will put the waiting on a separate thread, that is not the main one.

In my case, I had a list of commands to execute... so I first created a Queue and added all commands there, then I created a method "RunNextCommand" that dequeues the Element and runs the command, and if one of the commands is "downloadafile", then I just run the asyncdownload, and run one more "RunNextCommand" from the DownloadFileCompleted event.

This way you don't use DoEvents() (that is always a very bad idea), your CPU doesn't runs 100%, and your code is beautiful and clean ;-)

Thank you to myself. I'm welcome. Bye.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM