This is my whole source code. I want to download x files (lets assume we now have 2 files we want to download).
My main Point is to wait for all Downloads to complete and then proceed. I tried several points.
Task.WhenAll(List) -> Not working in my way of implementation
await -> impossibly in MainWindow function without async.
Workflow should be the following. Download started -> All Files Downloaded -> Show the Debug.Print
Atm: Source Code Output is -> All Downloads done "Download completed" "Download completed"
Should be: "Download completed" "Download completed" All Downloads done
Working for hours and no tiny step further to solve the problem. It is a WPF Application.
private volatile bool _download_completed;
public bool DownloadCompleted { get { return _download_completed; } }
public MainWindow()
{
InitializeComponent();
ProcessService.FillProcessData();
ProcessService.CloseAllProcesses();
DownloadHelper.AddDownloadFiles();
foreach(KeyValuePair<string,Uri> file in DownloadHelper.DownloadFiles)
{
DownloadFile(file.Key, file.Value);
}
Debug.Print("All Downloads done.");
}
private void DownloadFile(string Filename, Uri Uri)
{
Console.WriteLine(Filename + " " + Uri);
_download_completed = false;
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
client.DownloadFileTaskAsync(Uri, Filename);
}
private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
this.Dispatcher.Invoke(() => {
progressBar.Value = e.ProgressPercentage;
StatusLabel.Content = e.ProgressPercentage + " % complete... ( " + e.BytesReceived + " / " + e.TotalBytesToReceive + ")";
});
}
private void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
Console.WriteLine("Download completed");
this.Dispatcher.Invoke(() =>
{
StatusLabel.Content = "Download Finished";
});
_download_completed = true;
}
}
You need to use tasks to achieve this
First make your download function async
:
private async TaskDownloadFile(string Filename, Uri Uri)
{
Console.WriteLine(Filename + " " + Uri);
_download_completed = false;
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadFileCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
await client.DownloadFileTaskAsync(Uri, Filename);
}
Make the method async
and await
the DownloadFileTaskAsync
method.
I would suggest to remove the events for DownloadFileCompeted
and DownloadProgressChanged
if you will do multiple downloads they don't make much sense.
Now that you have made the method async
do the following:
var file1DownloadTask = TaskDownloadFile("filename","url");
var file2DownloadTask = TaskDownloadFile("filename","url");
At this point your have two tasks:
You can use the Task.WaitAll(list_of_taks_goes_here)
Task.WaitAll(file1DownloadTask,file2DownloadTask )
The wait
all method will wait for all the tasks to finished so the next line of code is called after those two tasks have finished:
Then you can do change the UI or whatever you need to do after the Task.WaitAll
line:
You could also do the following:
await TaskDownloadFile("filename","url");
await TaskDownloadFile("filename2","url");
Which will wait for the downloads to finish before moving on to next line but this way you have to know all the files at the time your write the code, with the first method you could have a list of files from which you could build the tasks and pass them to Task.WaitAll
.